Statistics
| Branch: | Revision:

root / hw / ppc.c @ beb811bd

History | View | Annotate | Download (18.4 kB)

1 a541f297 bellard
/*
2 a541f297 bellard
 * QEMU generic PPC hardware System Emulator
3 a541f297 bellard
 * 
4 76a66253 j_mayer
 * Copyright (c) 2003-2007 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 fd0bbb12 bellard
#include "m48t59.h"
26 a541f297 bellard
27 47103572 j_mayer
extern FILE *logfile;
28 47103572 j_mayer
extern int loglevel;
29 47103572 j_mayer
30 47103572 j_mayer
/*****************************************************************************/
31 47103572 j_mayer
/* PowerPC internal fake IRQ controller
32 47103572 j_mayer
 * used to manage multiple sources hardware events
33 47103572 j_mayer
 */
34 47103572 j_mayer
/* XXX: should be protected */
35 47103572 j_mayer
void ppc_set_irq (void *opaque, int n_IRQ, int level)
36 47103572 j_mayer
{
37 47103572 j_mayer
    CPUState *env;
38 47103572 j_mayer
39 47103572 j_mayer
    env = opaque;
40 47103572 j_mayer
    if (level) {
41 47103572 j_mayer
        env->pending_interrupts |= 1 << n_IRQ;
42 47103572 j_mayer
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
43 47103572 j_mayer
    } else {
44 47103572 j_mayer
        env->pending_interrupts &= ~(1 << n_IRQ);
45 47103572 j_mayer
        if (env->pending_interrupts == 0)
46 47103572 j_mayer
            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
47 47103572 j_mayer
    }
48 47103572 j_mayer
#if 0
49 47103572 j_mayer
    printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__,
50 47103572 j_mayer
           env, n_IRQ, level, env->pending_interrupts, env->interrupt_request);
51 47103572 j_mayer
#endif
52 47103572 j_mayer
}
53 47103572 j_mayer
54 47103572 j_mayer
/* External IRQ callback from OpenPIC IRQ controller */
55 47103572 j_mayer
void ppc_openpic_irq (void *opaque, int n_IRQ, int level)
56 47103572 j_mayer
{
57 47103572 j_mayer
    switch (n_IRQ) {
58 47103572 j_mayer
    case OPENPIC_EVT_INT:
59 47103572 j_mayer
        n_IRQ = PPC_INTERRUPT_EXT;
60 47103572 j_mayer
        break;
61 47103572 j_mayer
    case OPENPIC_EVT_CINT:
62 47103572 j_mayer
        /* On PowerPC BookE, critical input use vector 0 */
63 47103572 j_mayer
        n_IRQ = PPC_INTERRUPT_RESET;
64 47103572 j_mayer
        break;
65 47103572 j_mayer
    case OPENPIC_EVT_MCK:
66 47103572 j_mayer
        n_IRQ = PPC_INTERRUPT_MCK;
67 47103572 j_mayer
        break;
68 47103572 j_mayer
    case OPENPIC_EVT_DEBUG:
69 47103572 j_mayer
        n_IRQ = PPC_INTERRUPT_DEBUG;
70 47103572 j_mayer
        break;
71 47103572 j_mayer
    case OPENPIC_EVT_RESET:
72 47103572 j_mayer
        qemu_system_reset_request();
73 47103572 j_mayer
        return;
74 47103572 j_mayer
    }
75 47103572 j_mayer
    ppc_set_irq(opaque, n_IRQ, level);
76 47103572 j_mayer
}
77 47103572 j_mayer
78 9fddaa0c bellard
/*****************************************************************************/
79 9fddaa0c bellard
/* PPC time base and decrementer emulation */
80 9fddaa0c bellard
//#define DEBUG_TB
81 9fddaa0c bellard
82 9fddaa0c bellard
struct ppc_tb_t {
83 9fddaa0c bellard
    /* Time base management */
84 9fddaa0c bellard
    int64_t  tb_offset;    /* Compensation               */
85 9fddaa0c bellard
    uint32_t tb_freq;      /* TB frequency               */
86 9fddaa0c bellard
    /* Decrementer management */
87 9fddaa0c bellard
    uint64_t decr_next;    /* Tick for next decr interrupt  */
88 9fddaa0c bellard
    struct QEMUTimer *decr_timer;
89 47103572 j_mayer
    void *opaque;
90 9fddaa0c bellard
};
91 9fddaa0c bellard
92 9fddaa0c bellard
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
93 9fddaa0c bellard
{
94 9fddaa0c bellard
    /* TB time in tb periods */
95 9fddaa0c bellard
    return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
96 76a66253 j_mayer
                    tb_env->tb_freq, ticks_per_sec);
97 9fddaa0c bellard
}
98 9fddaa0c bellard
99 9fddaa0c bellard
uint32_t cpu_ppc_load_tbl (CPUState *env)
100 9fddaa0c bellard
{
101 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
102 9fddaa0c bellard
    uint64_t tb;
103 9fddaa0c bellard
104 9fddaa0c bellard
    tb = cpu_ppc_get_tb(tb_env);
105 9fddaa0c bellard
#ifdef DEBUG_TB
106 9fddaa0c bellard
    {
107 76a66253 j_mayer
        static int last_time;
108 76a66253 j_mayer
        int now;
109 76a66253 j_mayer
        now = time(NULL);
110 76a66253 j_mayer
        if (last_time != now) {
111 76a66253 j_mayer
            last_time = now;
112 76a66253 j_mayer
            printf("%s: tb=0x%016lx %d %08lx\n",
113 76a66253 j_mayer
                   __func__, tb, now, tb_env->tb_offset);
114 76a66253 j_mayer
        }
115 9fddaa0c bellard
    }
116 9fddaa0c bellard
#endif
117 9fddaa0c bellard
118 9fddaa0c bellard
    return tb & 0xFFFFFFFF;
119 9fddaa0c bellard
}
120 9fddaa0c bellard
121 9fddaa0c bellard
uint32_t cpu_ppc_load_tbu (CPUState *env)
122 9fddaa0c bellard
{
123 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
124 9fddaa0c bellard
    uint64_t tb;
125 9fddaa0c bellard
126 9fddaa0c bellard
    tb = cpu_ppc_get_tb(tb_env);
127 9fddaa0c bellard
#ifdef DEBUG_TB
128 9fddaa0c bellard
    printf("%s: tb=0x%016lx\n", __func__, tb);
129 9fddaa0c bellard
#endif
130 76a66253 j_mayer
131 9fddaa0c bellard
    return tb >> 32;
132 9fddaa0c bellard
}
133 9fddaa0c bellard
134 9fddaa0c bellard
static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
135 9fddaa0c bellard
{
136 9fddaa0c bellard
    tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
137 9fddaa0c bellard
        - qemu_get_clock(vm_clock);
138 9fddaa0c bellard
#ifdef DEBUG_TB
139 9fddaa0c bellard
    printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
140 9fddaa0c bellard
#endif
141 9fddaa0c bellard
}
142 9fddaa0c bellard
143 9fddaa0c bellard
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
144 9fddaa0c bellard
{
145 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
146 9fddaa0c bellard
147 9fddaa0c bellard
    cpu_ppc_store_tb(tb_env,
148 9fddaa0c bellard
                     ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
149 9fddaa0c bellard
}
150 9fddaa0c bellard
151 9fddaa0c bellard
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
152 9fddaa0c bellard
{
153 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
154 9fddaa0c bellard
155 9fddaa0c bellard
    cpu_ppc_store_tb(tb_env,
156 9fddaa0c bellard
                     ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
157 9fddaa0c bellard
}
158 9fddaa0c bellard
159 9fddaa0c bellard
uint32_t cpu_ppc_load_decr (CPUState *env)
160 9fddaa0c bellard
{
161 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
162 9fddaa0c bellard
    uint32_t decr;
163 4e588a4d bellard
    int64_t diff;
164 9fddaa0c bellard
165 4e588a4d bellard
    diff = tb_env->decr_next - qemu_get_clock(vm_clock);
166 4e588a4d bellard
    if (diff >= 0)
167 4e588a4d bellard
        decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
168 4e588a4d bellard
    else
169 4e588a4d bellard
        decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
170 fd0bbb12 bellard
#if defined(DEBUG_TB)
171 9fddaa0c bellard
    printf("%s: 0x%08x\n", __func__, decr);
172 9fddaa0c bellard
#endif
173 76a66253 j_mayer
174 9fddaa0c bellard
    return decr;
175 9fddaa0c bellard
}
176 9fddaa0c bellard
177 9fddaa0c bellard
/* When decrementer expires,
178 9fddaa0c bellard
 * all we need to do is generate or queue a CPU exception
179 9fddaa0c bellard
 */
180 9fddaa0c bellard
static inline void cpu_ppc_decr_excp (CPUState *env)
181 9fddaa0c bellard
{
182 9fddaa0c bellard
    /* Raise it */
183 9fddaa0c bellard
#ifdef DEBUG_TB
184 9fddaa0c bellard
    printf("raise decrementer exception\n");
185 9fddaa0c bellard
#endif
186 47103572 j_mayer
    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
187 9fddaa0c bellard
}
188 9fddaa0c bellard
189 9fddaa0c bellard
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
190 9fddaa0c bellard
                                 uint32_t value, int is_excp)
191 9fddaa0c bellard
{
192 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
193 9fddaa0c bellard
    uint64_t now, next;
194 9fddaa0c bellard
195 9fddaa0c bellard
#ifdef DEBUG_TB
196 9fddaa0c bellard
    printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
197 9fddaa0c bellard
#endif
198 9fddaa0c bellard
    now = qemu_get_clock(vm_clock);
199 9fddaa0c bellard
    next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
200 9fddaa0c bellard
    if (is_excp)
201 9fddaa0c bellard
        next += tb_env->decr_next - now;
202 9fddaa0c bellard
    if (next == now)
203 76a66253 j_mayer
        next++;
204 9fddaa0c bellard
    tb_env->decr_next = next;
205 9fddaa0c bellard
    /* Adjust timer */
206 9fddaa0c bellard
    qemu_mod_timer(tb_env->decr_timer, next);
207 9fddaa0c bellard
    /* If we set a negative value and the decrementer was positive,
208 9fddaa0c bellard
     * raise an exception.
209 9fddaa0c bellard
     */
210 9fddaa0c bellard
    if ((value & 0x80000000) && !(decr & 0x80000000))
211 76a66253 j_mayer
        cpu_ppc_decr_excp(env);
212 9fddaa0c bellard
}
213 9fddaa0c bellard
214 9fddaa0c bellard
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
215 9fddaa0c bellard
{
216 9fddaa0c bellard
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
217 9fddaa0c bellard
}
218 9fddaa0c bellard
219 9fddaa0c bellard
static void cpu_ppc_decr_cb (void *opaque)
220 9fddaa0c bellard
{
221 9fddaa0c bellard
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
222 9fddaa0c bellard
}
223 9fddaa0c bellard
224 9fddaa0c bellard
/* Set up (once) timebase frequency (in Hz) */
225 9fddaa0c bellard
ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
226 9fddaa0c bellard
{
227 9fddaa0c bellard
    ppc_tb_t *tb_env;
228 9fddaa0c bellard
229 9fddaa0c bellard
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
230 9fddaa0c bellard
    if (tb_env == NULL)
231 9fddaa0c bellard
        return NULL;
232 9fddaa0c bellard
    env->tb_env = tb_env;
233 9fddaa0c bellard
    if (tb_env->tb_freq == 0 || 1) {
234 76a66253 j_mayer
        tb_env->tb_freq = freq;
235 76a66253 j_mayer
        /* Create new timer */
236 76a66253 j_mayer
        tb_env->decr_timer =
237 9fddaa0c bellard
            qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
238 76a66253 j_mayer
        /* There is a bug in Linux 2.4 kernels:
239 76a66253 j_mayer
         * if a decrementer exception is pending when it enables msr_ee,
240 76a66253 j_mayer
         * it's not ready to handle it...
241 76a66253 j_mayer
         */
242 76a66253 j_mayer
        _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
243 9fddaa0c bellard
    }
244 9fddaa0c bellard
245 9fddaa0c bellard
    return tb_env;
246 9fddaa0c bellard
}
247 9fddaa0c bellard
248 76a66253 j_mayer
/* Specific helpers for POWER & PowerPC 601 RTC */
249 76a66253 j_mayer
ppc_tb_t *cpu_ppc601_rtc_init (CPUState *env)
250 76a66253 j_mayer
{
251 76a66253 j_mayer
    return cpu_ppc_tb_init(env, 7812500);
252 76a66253 j_mayer
}
253 76a66253 j_mayer
254 76a66253 j_mayer
void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
255 76a66253 j_mayer
__attribute__ (( alias ("cpu_ppc_store_tbu") ));
256 76a66253 j_mayer
257 76a66253 j_mayer
uint32_t cpu_ppc601_load_rtcu (CPUState *env)
258 76a66253 j_mayer
__attribute__ (( alias ("cpu_ppc_load_tbu") ));
259 76a66253 j_mayer
260 76a66253 j_mayer
void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
261 76a66253 j_mayer
{
262 76a66253 j_mayer
    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
263 76a66253 j_mayer
}
264 76a66253 j_mayer
265 76a66253 j_mayer
uint32_t cpu_ppc601_load_rtcl (CPUState *env)
266 76a66253 j_mayer
{
267 76a66253 j_mayer
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
268 76a66253 j_mayer
}
269 76a66253 j_mayer
270 636aaad7 j_mayer
/*****************************************************************************/
271 76a66253 j_mayer
/* Embedded PowerPC timers */
272 636aaad7 j_mayer
273 636aaad7 j_mayer
/* PIT, FIT & WDT */
274 636aaad7 j_mayer
typedef struct ppcemb_timer_t ppcemb_timer_t;
275 636aaad7 j_mayer
struct ppcemb_timer_t {
276 636aaad7 j_mayer
    uint64_t pit_reload;  /* PIT auto-reload value        */
277 636aaad7 j_mayer
    uint64_t fit_next;    /* Tick for next FIT interrupt  */
278 636aaad7 j_mayer
    struct QEMUTimer *fit_timer;
279 636aaad7 j_mayer
    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
280 636aaad7 j_mayer
    struct QEMUTimer *wdt_timer;
281 636aaad7 j_mayer
};
282 636aaad7 j_mayer
   
283 636aaad7 j_mayer
/* Fixed interval timer */
284 636aaad7 j_mayer
static void cpu_4xx_fit_cb (void *opaque)
285 636aaad7 j_mayer
{
286 636aaad7 j_mayer
    CPUState *env;
287 636aaad7 j_mayer
    ppc_tb_t *tb_env;
288 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
289 636aaad7 j_mayer
    uint64_t now, next;
290 636aaad7 j_mayer
291 636aaad7 j_mayer
    env = opaque;
292 636aaad7 j_mayer
    tb_env = env->tb_env;
293 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
294 636aaad7 j_mayer
    now = qemu_get_clock(vm_clock);
295 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
296 636aaad7 j_mayer
    case 0:
297 636aaad7 j_mayer
        next = 1 << 9;
298 636aaad7 j_mayer
        break;
299 636aaad7 j_mayer
    case 1:
300 636aaad7 j_mayer
        next = 1 << 13;
301 636aaad7 j_mayer
        break;
302 636aaad7 j_mayer
    case 2:
303 636aaad7 j_mayer
        next = 1 << 17;
304 636aaad7 j_mayer
        break;
305 636aaad7 j_mayer
    case 3:
306 636aaad7 j_mayer
        next = 1 << 21;
307 636aaad7 j_mayer
        break;
308 636aaad7 j_mayer
    default:
309 636aaad7 j_mayer
        /* Cannot occur, but makes gcc happy */
310 636aaad7 j_mayer
        return;
311 636aaad7 j_mayer
    }
312 636aaad7 j_mayer
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
313 636aaad7 j_mayer
    if (next == now)
314 636aaad7 j_mayer
        next++;
315 636aaad7 j_mayer
    qemu_mod_timer(ppcemb_timer->fit_timer, next);
316 636aaad7 j_mayer
    tb_env->decr_next = next;
317 636aaad7 j_mayer
    env->spr[SPR_40x_TSR] |= 1 << 26;
318 636aaad7 j_mayer
    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
319 636aaad7 j_mayer
        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
320 636aaad7 j_mayer
    if (loglevel) {
321 636aaad7 j_mayer
        fprintf(logfile, "%s: ir %d TCR %08x TSR %08x\n", __func__,
322 636aaad7 j_mayer
                (env->spr[SPR_40x_TCR] >> 23) & 0x1,
323 636aaad7 j_mayer
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
324 636aaad7 j_mayer
    }
325 636aaad7 j_mayer
}
326 636aaad7 j_mayer
327 636aaad7 j_mayer
/* Programmable interval timer */
328 636aaad7 j_mayer
static void cpu_4xx_pit_cb (void *opaque)
329 76a66253 j_mayer
{
330 636aaad7 j_mayer
    CPUState *env;
331 636aaad7 j_mayer
    ppc_tb_t *tb_env;
332 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
333 636aaad7 j_mayer
    uint64_t now, next;
334 636aaad7 j_mayer
335 636aaad7 j_mayer
    env = opaque;
336 636aaad7 j_mayer
    tb_env = env->tb_env;
337 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
338 636aaad7 j_mayer
    now = qemu_get_clock(vm_clock);
339 636aaad7 j_mayer
    if ((env->spr[SPR_40x_TCR] >> 22) & 0x1) {
340 636aaad7 j_mayer
        /* Auto reload */
341 636aaad7 j_mayer
        next = now + muldiv64(ppcemb_timer->pit_reload,
342 636aaad7 j_mayer
                              ticks_per_sec, tb_env->tb_freq);
343 636aaad7 j_mayer
        if (next == now)
344 636aaad7 j_mayer
            next++;
345 636aaad7 j_mayer
        qemu_mod_timer(tb_env->decr_timer, next);
346 636aaad7 j_mayer
        tb_env->decr_next = next;
347 636aaad7 j_mayer
    }
348 636aaad7 j_mayer
    env->spr[SPR_40x_TSR] |= 1 << 27;
349 636aaad7 j_mayer
    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
350 636aaad7 j_mayer
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
351 636aaad7 j_mayer
    if (loglevel) {
352 636aaad7 j_mayer
        fprintf(logfile, "%s: ar %d ir %d TCR %08x TSR %08x %08lx\n", __func__,
353 636aaad7 j_mayer
                (env->spr[SPR_40x_TCR] >> 22) & 0x1,
354 636aaad7 j_mayer
                (env->spr[SPR_40x_TCR] >> 26) & 0x1,
355 636aaad7 j_mayer
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
356 636aaad7 j_mayer
                ppcemb_timer->pit_reload);
357 636aaad7 j_mayer
    }
358 636aaad7 j_mayer
}
359 636aaad7 j_mayer
360 636aaad7 j_mayer
/* Watchdog timer */
361 636aaad7 j_mayer
static void cpu_4xx_wdt_cb (void *opaque)
362 636aaad7 j_mayer
{
363 636aaad7 j_mayer
    CPUState *env;
364 636aaad7 j_mayer
    ppc_tb_t *tb_env;
365 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
366 636aaad7 j_mayer
    uint64_t now, next;
367 636aaad7 j_mayer
368 636aaad7 j_mayer
    env = opaque;
369 636aaad7 j_mayer
    tb_env = env->tb_env;
370 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
371 636aaad7 j_mayer
    now = qemu_get_clock(vm_clock);
372 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
373 636aaad7 j_mayer
    case 0:
374 636aaad7 j_mayer
        next = 1 << 17;
375 636aaad7 j_mayer
        break;
376 636aaad7 j_mayer
    case 1:
377 636aaad7 j_mayer
        next = 1 << 21;
378 636aaad7 j_mayer
        break;
379 636aaad7 j_mayer
    case 2:
380 636aaad7 j_mayer
        next = 1 << 25;
381 636aaad7 j_mayer
        break;
382 636aaad7 j_mayer
    case 3:
383 636aaad7 j_mayer
        next = 1 << 29;
384 636aaad7 j_mayer
        break;
385 636aaad7 j_mayer
    default:
386 636aaad7 j_mayer
        /* Cannot occur, but makes gcc happy */
387 636aaad7 j_mayer
        return;
388 636aaad7 j_mayer
    }
389 636aaad7 j_mayer
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
390 636aaad7 j_mayer
    if (next == now)
391 636aaad7 j_mayer
        next++;
392 636aaad7 j_mayer
    if (loglevel) {
393 636aaad7 j_mayer
        fprintf(logfile, "%s: TCR %08x TSR %08x\n", __func__,
394 636aaad7 j_mayer
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
395 636aaad7 j_mayer
    }
396 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
397 636aaad7 j_mayer
    case 0x0:
398 636aaad7 j_mayer
    case 0x1:
399 636aaad7 j_mayer
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
400 636aaad7 j_mayer
        ppcemb_timer->wdt_next = next;
401 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= 1 << 31;
402 636aaad7 j_mayer
        break;
403 636aaad7 j_mayer
    case 0x2:
404 636aaad7 j_mayer
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
405 636aaad7 j_mayer
        ppcemb_timer->wdt_next = next;
406 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= 1 << 30;
407 636aaad7 j_mayer
        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
408 636aaad7 j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
409 636aaad7 j_mayer
        break;
410 636aaad7 j_mayer
    case 0x3:
411 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] &= ~0x30000000;
412 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
413 636aaad7 j_mayer
        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
414 636aaad7 j_mayer
        case 0x0:
415 636aaad7 j_mayer
            /* No reset */
416 636aaad7 j_mayer
            break;
417 636aaad7 j_mayer
        case 0x1: /* Core reset */
418 636aaad7 j_mayer
        case 0x2: /* Chip reset */
419 636aaad7 j_mayer
        case 0x3: /* System reset */
420 636aaad7 j_mayer
            qemu_system_reset_request();
421 636aaad7 j_mayer
            return;
422 636aaad7 j_mayer
        }
423 636aaad7 j_mayer
    }
424 76a66253 j_mayer
}
425 76a66253 j_mayer
426 76a66253 j_mayer
void store_40x_pit (CPUState *env, target_ulong val)
427 76a66253 j_mayer
{
428 636aaad7 j_mayer
    ppc_tb_t *tb_env;
429 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
430 636aaad7 j_mayer
    uint64_t now, next;
431 636aaad7 j_mayer
432 636aaad7 j_mayer
    tb_env = env->tb_env;
433 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
434 636aaad7 j_mayer
    if (loglevel)
435 636aaad7 j_mayer
        fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
436 636aaad7 j_mayer
    ppcemb_timer->pit_reload = val;
437 636aaad7 j_mayer
    if (val == 0) {
438 636aaad7 j_mayer
        /* Stop PIT */
439 636aaad7 j_mayer
        if (loglevel)
440 636aaad7 j_mayer
            fprintf(logfile, "%s: stop PIT\n", __func__);
441 636aaad7 j_mayer
        qemu_del_timer(tb_env->decr_timer);
442 636aaad7 j_mayer
    } else {
443 636aaad7 j_mayer
        if (loglevel)
444 636aaad7 j_mayer
            fprintf(logfile, "%s: start PIT 0x%08x\n", __func__, val);
445 636aaad7 j_mayer
        now = qemu_get_clock(vm_clock);
446 636aaad7 j_mayer
        next = now + muldiv64(val, ticks_per_sec, tb_env->tb_freq);
447 636aaad7 j_mayer
         if (next == now)
448 636aaad7 j_mayer
            next++;
449 636aaad7 j_mayer
        qemu_mod_timer(tb_env->decr_timer, next);
450 636aaad7 j_mayer
        tb_env->decr_next = next;
451 636aaad7 j_mayer
    }
452 76a66253 j_mayer
}
453 76a66253 j_mayer
454 636aaad7 j_mayer
target_ulong load_40x_pit (CPUState *env)
455 76a66253 j_mayer
{
456 636aaad7 j_mayer
    return cpu_ppc_load_decr(env);
457 76a66253 j_mayer
}
458 76a66253 j_mayer
459 76a66253 j_mayer
void store_booke_tsr (CPUState *env, target_ulong val)
460 76a66253 j_mayer
{
461 636aaad7 j_mayer
    env->spr[SPR_40x_TSR] = val & 0xFC000000;
462 636aaad7 j_mayer
}
463 636aaad7 j_mayer
464 636aaad7 j_mayer
void store_booke_tcr (CPUState *env, target_ulong val)
465 636aaad7 j_mayer
{
466 636aaad7 j_mayer
    /* We don't update timers now. Maybe we should... */
467 636aaad7 j_mayer
    env->spr[SPR_40x_TCR] = val & 0xFF800000;
468 636aaad7 j_mayer
}
469 636aaad7 j_mayer
470 636aaad7 j_mayer
void ppc_emb_timers_init (CPUState *env)
471 636aaad7 j_mayer
{
472 636aaad7 j_mayer
    ppc_tb_t *tb_env;
473 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
474 636aaad7 j_mayer
475 636aaad7 j_mayer
    tb_env = env->tb_env;
476 636aaad7 j_mayer
    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
477 636aaad7 j_mayer
    tb_env->opaque = ppcemb_timer;
478 636aaad7 j_mayer
    if (loglevel)
479 636aaad7 j_mayer
        fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
480 636aaad7 j_mayer
    if (ppcemb_timer != NULL) {
481 636aaad7 j_mayer
        /* We use decr timer for PIT */
482 636aaad7 j_mayer
        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
483 636aaad7 j_mayer
        ppcemb_timer->fit_timer =
484 636aaad7 j_mayer
            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
485 636aaad7 j_mayer
        ppcemb_timer->wdt_timer =
486 636aaad7 j_mayer
            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
487 636aaad7 j_mayer
    }
488 76a66253 j_mayer
}
489 76a66253 j_mayer
490 9fddaa0c bellard
#if 0
491 9fddaa0c bellard
/*****************************************************************************/
492 9fddaa0c bellard
/* Handle system reset (for now, just stop emulation) */
493 9fddaa0c bellard
void cpu_ppc_reset (CPUState *env)
494 9fddaa0c bellard
{
495 9fddaa0c bellard
    printf("Reset asked... Stop emulation\n");
496 9fddaa0c bellard
    abort();
497 9fddaa0c bellard
}
498 9fddaa0c bellard
#endif
499 9fddaa0c bellard
500 64201201 bellard
/*****************************************************************************/
501 64201201 bellard
/* Debug port */
502 fd0bbb12 bellard
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
503 64201201 bellard
{
504 64201201 bellard
    addr &= 0xF;
505 64201201 bellard
    switch (addr) {
506 64201201 bellard
    case 0:
507 64201201 bellard
        printf("%c", val);
508 64201201 bellard
        break;
509 64201201 bellard
    case 1:
510 64201201 bellard
        printf("\n");
511 64201201 bellard
        fflush(stdout);
512 64201201 bellard
        break;
513 64201201 bellard
    case 2:
514 64201201 bellard
        printf("Set loglevel to %04x\n", val);
515 fd0bbb12 bellard
        cpu_set_log(val | 0x100);
516 64201201 bellard
        break;
517 64201201 bellard
    }
518 64201201 bellard
}
519 64201201 bellard
520 64201201 bellard
/*****************************************************************************/
521 64201201 bellard
/* NVRAM helpers */
522 64201201 bellard
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
523 64201201 bellard
{
524 819385c5 bellard
    m48t59_write(nvram, addr, value);
525 64201201 bellard
}
526 64201201 bellard
527 64201201 bellard
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
528 64201201 bellard
{
529 819385c5 bellard
    return m48t59_read(nvram, addr);
530 64201201 bellard
}
531 64201201 bellard
532 64201201 bellard
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
533 64201201 bellard
{
534 819385c5 bellard
    m48t59_write(nvram, addr, value >> 8);
535 819385c5 bellard
    m48t59_write(nvram, addr + 1, value & 0xFF);
536 64201201 bellard
}
537 64201201 bellard
538 64201201 bellard
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
539 64201201 bellard
{
540 64201201 bellard
    uint16_t tmp;
541 64201201 bellard
542 819385c5 bellard
    tmp = m48t59_read(nvram, addr) << 8;
543 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 1);
544 64201201 bellard
    return tmp;
545 64201201 bellard
}
546 64201201 bellard
547 64201201 bellard
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
548 64201201 bellard
{
549 819385c5 bellard
    m48t59_write(nvram, addr, value >> 24);
550 819385c5 bellard
    m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
551 819385c5 bellard
    m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
552 819385c5 bellard
    m48t59_write(nvram, addr + 3, value & 0xFF);
553 64201201 bellard
}
554 64201201 bellard
555 64201201 bellard
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
556 64201201 bellard
{
557 64201201 bellard
    uint32_t tmp;
558 64201201 bellard
559 819385c5 bellard
    tmp = m48t59_read(nvram, addr) << 24;
560 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 1) << 16;
561 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 2) << 8;
562 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 3);
563 76a66253 j_mayer
564 64201201 bellard
    return tmp;
565 64201201 bellard
}
566 64201201 bellard
567 64201201 bellard
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
568 64201201 bellard
                       const unsigned char *str, uint32_t max)
569 64201201 bellard
{
570 64201201 bellard
    int i;
571 64201201 bellard
572 64201201 bellard
    for (i = 0; i < max && str[i] != '\0'; i++) {
573 819385c5 bellard
        m48t59_write(nvram, addr + i, str[i]);
574 64201201 bellard
    }
575 819385c5 bellard
    m48t59_write(nvram, addr + max - 1, '\0');
576 64201201 bellard
}
577 64201201 bellard
578 64201201 bellard
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
579 64201201 bellard
{
580 64201201 bellard
    int i;
581 64201201 bellard
582 64201201 bellard
    memset(dst, 0, max);
583 64201201 bellard
    for (i = 0; i < max; i++) {
584 64201201 bellard
        dst[i] = NVRAM_get_byte(nvram, addr + i);
585 64201201 bellard
        if (dst[i] == '\0')
586 64201201 bellard
            break;
587 64201201 bellard
    }
588 64201201 bellard
589 64201201 bellard
    return i;
590 64201201 bellard
}
591 64201201 bellard
592 64201201 bellard
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
593 64201201 bellard
{
594 64201201 bellard
    uint16_t tmp;
595 64201201 bellard
    uint16_t pd, pd1, pd2;
596 64201201 bellard
597 64201201 bellard
    tmp = prev >> 8;
598 64201201 bellard
    pd = prev ^ value;
599 64201201 bellard
    pd1 = pd & 0x000F;
600 64201201 bellard
    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
601 64201201 bellard
    tmp ^= (pd1 << 3) | (pd1 << 8);
602 64201201 bellard
    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
603 64201201 bellard
604 64201201 bellard
    return tmp;
605 64201201 bellard
}
606 64201201 bellard
607 64201201 bellard
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
608 64201201 bellard
{
609 64201201 bellard
    uint32_t i;
610 64201201 bellard
    uint16_t crc = 0xFFFF;
611 64201201 bellard
    int odd;
612 64201201 bellard
613 64201201 bellard
    odd = count & 1;
614 64201201 bellard
    count &= ~1;
615 64201201 bellard
    for (i = 0; i != count; i++) {
616 76a66253 j_mayer
        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
617 64201201 bellard
    }
618 64201201 bellard
    if (odd) {
619 76a66253 j_mayer
        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
620 64201201 bellard
    }
621 64201201 bellard
622 64201201 bellard
    return crc;
623 64201201 bellard
}
624 64201201 bellard
625 fd0bbb12 bellard
#define CMDLINE_ADDR 0x017ff000
626 fd0bbb12 bellard
627 64201201 bellard
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
628 64201201 bellard
                          const unsigned char *arch,
629 64201201 bellard
                          uint32_t RAM_size, int boot_device,
630 64201201 bellard
                          uint32_t kernel_image, uint32_t kernel_size,
631 fd0bbb12 bellard
                          const char *cmdline,
632 64201201 bellard
                          uint32_t initrd_image, uint32_t initrd_size,
633 fd0bbb12 bellard
                          uint32_t NVRAM_image,
634 fd0bbb12 bellard
                          int width, int height, int depth)
635 64201201 bellard
{
636 64201201 bellard
    uint16_t crc;
637 64201201 bellard
638 64201201 bellard
    /* Set parameters for Open Hack'Ware BIOS */
639 64201201 bellard
    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
640 64201201 bellard
    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
641 64201201 bellard
    NVRAM_set_word(nvram,   0x14, NVRAM_size);
642 64201201 bellard
    NVRAM_set_string(nvram, 0x20, arch, 16);
643 64201201 bellard
    NVRAM_set_lword(nvram,  0x30, RAM_size);
644 64201201 bellard
    NVRAM_set_byte(nvram,   0x34, boot_device);
645 64201201 bellard
    NVRAM_set_lword(nvram,  0x38, kernel_image);
646 64201201 bellard
    NVRAM_set_lword(nvram,  0x3C, kernel_size);
647 fd0bbb12 bellard
    if (cmdline) {
648 fd0bbb12 bellard
        /* XXX: put the cmdline in NVRAM too ? */
649 fd0bbb12 bellard
        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
650 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
651 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
652 fd0bbb12 bellard
    } else {
653 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x40, 0);
654 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x44, 0);
655 fd0bbb12 bellard
    }
656 64201201 bellard
    NVRAM_set_lword(nvram,  0x48, initrd_image);
657 64201201 bellard
    NVRAM_set_lword(nvram,  0x4C, initrd_size);
658 64201201 bellard
    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
659 fd0bbb12 bellard
660 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x54, width);
661 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x56, height);
662 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x58, depth);
663 fd0bbb12 bellard
    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
664 fd0bbb12 bellard
    NVRAM_set_word(nvram,  0xFC, crc);
665 64201201 bellard
666 64201201 bellard
    return 0;
667 a541f297 bellard
}