Statistics
| Branch: | Revision:

root / hw / ppc.c @ b30bb3a2

History | View | Annotate | Download (32.6 kB)

1 a541f297 bellard
/*
2 e9df014c j_mayer
 * QEMU generic PowerPC 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 e9df014c j_mayer
//#define PPC_DEBUG_IRQ
28 4b6d0a4c j_mayer
//#define PPC_DEBUG_TB
29 e9df014c j_mayer
30 47103572 j_mayer
extern FILE *logfile;
31 47103572 j_mayer
extern int loglevel;
32 47103572 j_mayer
33 e9df014c j_mayer
void ppc_set_irq (CPUState *env, int n_IRQ, int level)
34 47103572 j_mayer
{
35 47103572 j_mayer
    if (level) {
36 47103572 j_mayer
        env->pending_interrupts |= 1 << n_IRQ;
37 47103572 j_mayer
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
38 47103572 j_mayer
    } else {
39 47103572 j_mayer
        env->pending_interrupts &= ~(1 << n_IRQ);
40 47103572 j_mayer
        if (env->pending_interrupts == 0)
41 47103572 j_mayer
            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
42 47103572 j_mayer
    }
43 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
44 a496775f j_mayer
    if (loglevel & CPU_LOG_INT) {
45 a496775f j_mayer
        fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08x req %08x\n",
46 a496775f j_mayer
                __func__, env, n_IRQ, level,
47 a496775f j_mayer
                env->pending_interrupts, env->interrupt_request);
48 a496775f j_mayer
    }
49 47103572 j_mayer
#endif
50 47103572 j_mayer
}
51 47103572 j_mayer
52 e9df014c j_mayer
/* PowerPC 6xx / 7xx internal IRQ controller */
53 e9df014c j_mayer
static void ppc6xx_set_irq (void *opaque, int pin, int level)
54 d537cf6c pbrook
{
55 e9df014c j_mayer
    CPUState *env = opaque;
56 e9df014c j_mayer
    int cur_level;
57 d537cf6c pbrook
58 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
59 a496775f j_mayer
    if (loglevel & CPU_LOG_INT) {
60 a496775f j_mayer
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
61 a496775f j_mayer
                env, pin, level);
62 a496775f j_mayer
    }
63 e9df014c j_mayer
#endif
64 e9df014c j_mayer
    cur_level = (env->irq_input_state >> pin) & 1;
65 e9df014c j_mayer
    /* Don't generate spurious events */
66 24be5ae3 j_mayer
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
67 e9df014c j_mayer
        switch (pin) {
68 24be5ae3 j_mayer
        case PPC6xx_INPUT_INT:
69 24be5ae3 j_mayer
            /* Level sensitive - active high */
70 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
71 a496775f j_mayer
            if (loglevel & CPU_LOG_INT) {
72 a496775f j_mayer
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
73 a496775f j_mayer
                        __func__, level);
74 a496775f j_mayer
            }
75 e9df014c j_mayer
#endif
76 e9df014c j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
77 e9df014c j_mayer
            break;
78 24be5ae3 j_mayer
        case PPC6xx_INPUT_SMI:
79 e9df014c j_mayer
            /* Level sensitive - active high */
80 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
81 a496775f j_mayer
            if (loglevel & CPU_LOG_INT) {
82 a496775f j_mayer
                fprintf(logfile, "%s: set the SMI IRQ state to %d\n",
83 a496775f j_mayer
                        __func__, level);
84 a496775f j_mayer
            }
85 e9df014c j_mayer
#endif
86 e9df014c j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
87 e9df014c j_mayer
            break;
88 24be5ae3 j_mayer
        case PPC6xx_INPUT_MCP:
89 e9df014c j_mayer
            /* Negative edge sensitive */
90 e9df014c j_mayer
            /* XXX: TODO: actual reaction may depends on HID0 status
91 e9df014c j_mayer
             *            603/604/740/750: check HID0[EMCP]
92 e9df014c j_mayer
             */
93 e9df014c j_mayer
            if (cur_level == 1 && level == 0) {
94 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
95 a496775f j_mayer
                if (loglevel & CPU_LOG_INT) {
96 a496775f j_mayer
                    fprintf(logfile, "%s: raise machine check state\n",
97 a496775f j_mayer
                            __func__);
98 a496775f j_mayer
                }
99 e9df014c j_mayer
#endif
100 e9df014c j_mayer
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
101 e9df014c j_mayer
            }
102 e9df014c j_mayer
            break;
103 24be5ae3 j_mayer
        case PPC6xx_INPUT_CKSTP_IN:
104 e9df014c j_mayer
            /* Level sensitive - active low */
105 e9df014c j_mayer
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
106 e9df014c j_mayer
            if (level) {
107 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
108 a496775f j_mayer
                if (loglevel & CPU_LOG_INT) {
109 a496775f j_mayer
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
110 a496775f j_mayer
                }
111 e9df014c j_mayer
#endif
112 e9df014c j_mayer
                env->halted = 1;
113 e9df014c j_mayer
            } else {
114 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
115 a496775f j_mayer
                if (loglevel & CPU_LOG_INT) {
116 a496775f j_mayer
                    fprintf(logfile, "%s: restart the CPU\n", __func__);
117 a496775f j_mayer
                }
118 e9df014c j_mayer
#endif
119 e9df014c j_mayer
                env->halted = 0;
120 e9df014c j_mayer
            }
121 e9df014c j_mayer
            break;
122 24be5ae3 j_mayer
        case PPC6xx_INPUT_HRESET:
123 e9df014c j_mayer
            /* Level sensitive - active low */
124 e9df014c j_mayer
            if (level) {
125 e9df014c j_mayer
#if 0 // XXX: TOFIX
126 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
127 a496775f j_mayer
                if (loglevel & CPU_LOG_INT) {
128 a496775f j_mayer
                    fprintf(logfile, "%s: reset the CPU\n", __func__);
129 a496775f j_mayer
                }
130 e9df014c j_mayer
#endif
131 e9df014c j_mayer
                cpu_reset(env);
132 e9df014c j_mayer
#endif
133 e9df014c j_mayer
            }
134 e9df014c j_mayer
            break;
135 24be5ae3 j_mayer
        case PPC6xx_INPUT_SRESET:
136 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
137 a496775f j_mayer
            if (loglevel & CPU_LOG_INT) {
138 a496775f j_mayer
                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
139 a496775f j_mayer
                        __func__, level);
140 a496775f j_mayer
            }
141 e9df014c j_mayer
#endif
142 e9df014c j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
143 e9df014c j_mayer
            break;
144 e9df014c j_mayer
        default:
145 e9df014c j_mayer
            /* Unknown pin - do nothing */
146 e9df014c j_mayer
#if defined(PPC_DEBUG_IRQ)
147 a496775f j_mayer
            if (loglevel & CPU_LOG_INT) {
148 a496775f j_mayer
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
149 a496775f j_mayer
            }
150 e9df014c j_mayer
#endif
151 e9df014c j_mayer
            return;
152 e9df014c j_mayer
        }
153 e9df014c j_mayer
        if (level)
154 e9df014c j_mayer
            env->irq_input_state |= 1 << pin;
155 e9df014c j_mayer
        else
156 e9df014c j_mayer
            env->irq_input_state &= ~(1 << pin);
157 d537cf6c pbrook
    }
158 d537cf6c pbrook
}
159 d537cf6c pbrook
160 e9df014c j_mayer
void ppc6xx_irq_init (CPUState *env)
161 47103572 j_mayer
{
162 e9df014c j_mayer
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
163 47103572 j_mayer
}
164 47103572 j_mayer
165 d0dfae6e j_mayer
/* PowerPC 970 internal IRQ controller */
166 d0dfae6e j_mayer
static void ppc970_set_irq (void *opaque, int pin, int level)
167 d0dfae6e j_mayer
{
168 d0dfae6e j_mayer
    CPUState *env = opaque;
169 d0dfae6e j_mayer
    int cur_level;
170 d0dfae6e j_mayer
171 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
172 d0dfae6e j_mayer
    if (loglevel & CPU_LOG_INT) {
173 d0dfae6e j_mayer
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
174 d0dfae6e j_mayer
                env, pin, level);
175 d0dfae6e j_mayer
    }
176 d0dfae6e j_mayer
#endif
177 d0dfae6e j_mayer
    cur_level = (env->irq_input_state >> pin) & 1;
178 d0dfae6e j_mayer
    /* Don't generate spurious events */
179 d0dfae6e j_mayer
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
180 d0dfae6e j_mayer
        switch (pin) {
181 d0dfae6e j_mayer
        case PPC970_INPUT_INT:
182 d0dfae6e j_mayer
            /* Level sensitive - active high */
183 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
184 d0dfae6e j_mayer
            if (loglevel & CPU_LOG_INT) {
185 d0dfae6e j_mayer
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
186 d0dfae6e j_mayer
                        __func__, level);
187 d0dfae6e j_mayer
            }
188 d0dfae6e j_mayer
#endif
189 d0dfae6e j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
190 d0dfae6e j_mayer
            break;
191 d0dfae6e j_mayer
        case PPC970_INPUT_THINT:
192 d0dfae6e j_mayer
            /* Level sensitive - active high */
193 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
194 d0dfae6e j_mayer
            if (loglevel & CPU_LOG_INT) {
195 d0dfae6e j_mayer
                fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__,
196 d0dfae6e j_mayer
                        level);
197 d0dfae6e j_mayer
            }
198 d0dfae6e j_mayer
#endif
199 d0dfae6e j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
200 d0dfae6e j_mayer
            break;
201 d0dfae6e j_mayer
        case PPC970_INPUT_MCP:
202 d0dfae6e j_mayer
            /* Negative edge sensitive */
203 d0dfae6e j_mayer
            /* XXX: TODO: actual reaction may depends on HID0 status
204 d0dfae6e j_mayer
             *            603/604/740/750: check HID0[EMCP]
205 d0dfae6e j_mayer
             */
206 d0dfae6e j_mayer
            if (cur_level == 1 && level == 0) {
207 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
208 d0dfae6e j_mayer
                if (loglevel & CPU_LOG_INT) {
209 d0dfae6e j_mayer
                    fprintf(logfile, "%s: raise machine check state\n",
210 d0dfae6e j_mayer
                            __func__);
211 d0dfae6e j_mayer
                }
212 d0dfae6e j_mayer
#endif
213 d0dfae6e j_mayer
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
214 d0dfae6e j_mayer
            }
215 d0dfae6e j_mayer
            break;
216 d0dfae6e j_mayer
        case PPC970_INPUT_CKSTP:
217 d0dfae6e j_mayer
            /* Level sensitive - active low */
218 d0dfae6e j_mayer
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
219 d0dfae6e j_mayer
            if (level) {
220 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
221 d0dfae6e j_mayer
                if (loglevel & CPU_LOG_INT) {
222 d0dfae6e j_mayer
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
223 d0dfae6e j_mayer
                }
224 d0dfae6e j_mayer
#endif
225 d0dfae6e j_mayer
                env->halted = 1;
226 d0dfae6e j_mayer
            } else {
227 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
228 d0dfae6e j_mayer
                if (loglevel & CPU_LOG_INT) {
229 d0dfae6e j_mayer
                    fprintf(logfile, "%s: restart the CPU\n", __func__);
230 d0dfae6e j_mayer
                }
231 d0dfae6e j_mayer
#endif
232 d0dfae6e j_mayer
                env->halted = 0;
233 d0dfae6e j_mayer
            }
234 d0dfae6e j_mayer
            break;
235 d0dfae6e j_mayer
        case PPC970_INPUT_HRESET:
236 d0dfae6e j_mayer
            /* Level sensitive - active low */
237 d0dfae6e j_mayer
            if (level) {
238 d0dfae6e j_mayer
#if 0 // XXX: TOFIX
239 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
240 d0dfae6e j_mayer
                if (loglevel & CPU_LOG_INT) {
241 d0dfae6e j_mayer
                    fprintf(logfile, "%s: reset the CPU\n", __func__);
242 d0dfae6e j_mayer
                }
243 d0dfae6e j_mayer
#endif
244 d0dfae6e j_mayer
                cpu_reset(env);
245 d0dfae6e j_mayer
#endif
246 d0dfae6e j_mayer
            }
247 d0dfae6e j_mayer
            break;
248 d0dfae6e j_mayer
        case PPC970_INPUT_SRESET:
249 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
250 d0dfae6e j_mayer
            if (loglevel & CPU_LOG_INT) {
251 d0dfae6e j_mayer
                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
252 d0dfae6e j_mayer
                        __func__, level);
253 d0dfae6e j_mayer
            }
254 d0dfae6e j_mayer
#endif
255 d0dfae6e j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
256 d0dfae6e j_mayer
            break;
257 d0dfae6e j_mayer
        case PPC970_INPUT_TBEN:
258 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
259 d0dfae6e j_mayer
            if (loglevel & CPU_LOG_INT) {
260 d0dfae6e j_mayer
                fprintf(logfile, "%s: set the TBEN state to %d\n", __func__,
261 d0dfae6e j_mayer
                        level);
262 d0dfae6e j_mayer
            }
263 d0dfae6e j_mayer
#endif
264 d0dfae6e j_mayer
            /* XXX: TODO */
265 d0dfae6e j_mayer
            break;
266 d0dfae6e j_mayer
        default:
267 d0dfae6e j_mayer
            /* Unknown pin - do nothing */
268 d0dfae6e j_mayer
#if defined(PPC_DEBUG_IRQ)
269 d0dfae6e j_mayer
            if (loglevel & CPU_LOG_INT) {
270 d0dfae6e j_mayer
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
271 d0dfae6e j_mayer
            }
272 d0dfae6e j_mayer
#endif
273 d0dfae6e j_mayer
            return;
274 d0dfae6e j_mayer
        }
275 d0dfae6e j_mayer
        if (level)
276 d0dfae6e j_mayer
            env->irq_input_state |= 1 << pin;
277 d0dfae6e j_mayer
        else
278 d0dfae6e j_mayer
            env->irq_input_state &= ~(1 << pin);
279 d0dfae6e j_mayer
    }
280 d0dfae6e j_mayer
}
281 d0dfae6e j_mayer
282 d0dfae6e j_mayer
void ppc970_irq_init (CPUState *env)
283 d0dfae6e j_mayer
{
284 d0dfae6e j_mayer
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7);
285 d0dfae6e j_mayer
}
286 d0dfae6e j_mayer
287 24be5ae3 j_mayer
/* PowerPC 405 internal IRQ controller */
288 24be5ae3 j_mayer
static void ppc405_set_irq (void *opaque, int pin, int level)
289 24be5ae3 j_mayer
{
290 24be5ae3 j_mayer
    CPUState *env = opaque;
291 24be5ae3 j_mayer
    int cur_level;
292 24be5ae3 j_mayer
293 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
294 8ecc7913 j_mayer
    if (loglevel & CPU_LOG_INT) {
295 8ecc7913 j_mayer
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
296 8ecc7913 j_mayer
                env, pin, level);
297 8ecc7913 j_mayer
    }
298 24be5ae3 j_mayer
#endif
299 24be5ae3 j_mayer
    cur_level = (env->irq_input_state >> pin) & 1;
300 24be5ae3 j_mayer
    /* Don't generate spurious events */
301 24be5ae3 j_mayer
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
302 24be5ae3 j_mayer
        switch (pin) {
303 24be5ae3 j_mayer
        case PPC405_INPUT_RESET_SYS:
304 8ecc7913 j_mayer
            if (level) {
305 8ecc7913 j_mayer
#if defined(PPC_DEBUG_IRQ)
306 8ecc7913 j_mayer
                if (loglevel & CPU_LOG_INT) {
307 8ecc7913 j_mayer
                    fprintf(logfile, "%s: reset the PowerPC system\n",
308 8ecc7913 j_mayer
                            __func__);
309 8ecc7913 j_mayer
                }
310 8ecc7913 j_mayer
#endif
311 8ecc7913 j_mayer
                ppc40x_system_reset(env);
312 8ecc7913 j_mayer
            }
313 8ecc7913 j_mayer
            break;
314 24be5ae3 j_mayer
        case PPC405_INPUT_RESET_CHIP:
315 8ecc7913 j_mayer
            if (level) {
316 8ecc7913 j_mayer
#if defined(PPC_DEBUG_IRQ)
317 8ecc7913 j_mayer
                if (loglevel & CPU_LOG_INT) {
318 8ecc7913 j_mayer
                    fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
319 8ecc7913 j_mayer
                }
320 8ecc7913 j_mayer
#endif
321 8ecc7913 j_mayer
                ppc40x_chip_reset(env);
322 8ecc7913 j_mayer
            }
323 8ecc7913 j_mayer
            break;
324 24be5ae3 j_mayer
            /* No break here */
325 24be5ae3 j_mayer
        case PPC405_INPUT_RESET_CORE:
326 24be5ae3 j_mayer
            /* XXX: TODO: update DBSR[MRR] */
327 24be5ae3 j_mayer
            if (level) {
328 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
329 8ecc7913 j_mayer
                if (loglevel & CPU_LOG_INT) {
330 8ecc7913 j_mayer
                    fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
331 8ecc7913 j_mayer
                }
332 24be5ae3 j_mayer
#endif
333 8ecc7913 j_mayer
                ppc40x_core_reset(env);
334 24be5ae3 j_mayer
            }
335 24be5ae3 j_mayer
            break;
336 24be5ae3 j_mayer
        case PPC405_INPUT_CINT:
337 24be5ae3 j_mayer
            /* Level sensitive - active high */
338 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
339 8ecc7913 j_mayer
            if (loglevel & CPU_LOG_INT) {
340 8ecc7913 j_mayer
                fprintf(logfile, "%s: set the critical IRQ state to %d\n",
341 8ecc7913 j_mayer
                        __func__, level);
342 8ecc7913 j_mayer
            }
343 24be5ae3 j_mayer
#endif
344 24be5ae3 j_mayer
            /* XXX: TOFIX */
345 24be5ae3 j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
346 24be5ae3 j_mayer
            break;
347 24be5ae3 j_mayer
        case PPC405_INPUT_INT:
348 24be5ae3 j_mayer
            /* Level sensitive - active high */
349 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
350 a496775f j_mayer
            if (loglevel & CPU_LOG_INT) {
351 a496775f j_mayer
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
352 a496775f j_mayer
                        __func__, level);
353 a496775f j_mayer
            }
354 24be5ae3 j_mayer
#endif
355 24be5ae3 j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
356 24be5ae3 j_mayer
            break;
357 24be5ae3 j_mayer
        case PPC405_INPUT_HALT:
358 24be5ae3 j_mayer
            /* Level sensitive - active low */
359 24be5ae3 j_mayer
            if (level) {
360 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
361 a496775f j_mayer
                if (loglevel & CPU_LOG_INT) {
362 a496775f j_mayer
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
363 a496775f j_mayer
                }
364 24be5ae3 j_mayer
#endif
365 24be5ae3 j_mayer
                env->halted = 1;
366 24be5ae3 j_mayer
            } else {
367 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
368 a496775f j_mayer
                if (loglevel & CPU_LOG_INT) {
369 a496775f j_mayer
                    fprintf(logfile, "%s: restart the CPU\n", __func__);
370 a496775f j_mayer
                }
371 24be5ae3 j_mayer
#endif
372 24be5ae3 j_mayer
                env->halted = 0;
373 24be5ae3 j_mayer
            }
374 24be5ae3 j_mayer
            break;
375 24be5ae3 j_mayer
        case PPC405_INPUT_DEBUG:
376 24be5ae3 j_mayer
            /* Level sensitive - active high */
377 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
378 a496775f j_mayer
            if (loglevel & CPU_LOG_INT) {
379 a496775f j_mayer
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
380 a496775f j_mayer
                        __func__, level);
381 a496775f j_mayer
            }
382 24be5ae3 j_mayer
#endif
383 24be5ae3 j_mayer
            ppc_set_irq(env, EXCP_40x_DEBUG, level);
384 24be5ae3 j_mayer
            break;
385 24be5ae3 j_mayer
        default:
386 24be5ae3 j_mayer
            /* Unknown pin - do nothing */
387 24be5ae3 j_mayer
#if defined(PPC_DEBUG_IRQ)
388 a496775f j_mayer
            if (loglevel & CPU_LOG_INT) {
389 a496775f j_mayer
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
390 a496775f j_mayer
            }
391 24be5ae3 j_mayer
#endif
392 24be5ae3 j_mayer
            return;
393 24be5ae3 j_mayer
        }
394 24be5ae3 j_mayer
        if (level)
395 24be5ae3 j_mayer
            env->irq_input_state |= 1 << pin;
396 24be5ae3 j_mayer
        else
397 24be5ae3 j_mayer
            env->irq_input_state &= ~(1 << pin);
398 24be5ae3 j_mayer
    }
399 24be5ae3 j_mayer
}
400 24be5ae3 j_mayer
401 24be5ae3 j_mayer
void ppc405_irq_init (CPUState *env)
402 24be5ae3 j_mayer
{
403 24be5ae3 j_mayer
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc405_set_irq, env, 7);
404 24be5ae3 j_mayer
}
405 24be5ae3 j_mayer
406 9fddaa0c bellard
/*****************************************************************************/
407 e9df014c j_mayer
/* PowerPC time base and decrementer emulation */
408 9fddaa0c bellard
struct ppc_tb_t {
409 9fddaa0c bellard
    /* Time base management */
410 9fddaa0c bellard
    int64_t  tb_offset;    /* Compensation               */
411 9fddaa0c bellard
    uint32_t tb_freq;      /* TB frequency               */
412 9fddaa0c bellard
    /* Decrementer management */
413 9fddaa0c bellard
    uint64_t decr_next;    /* Tick for next decr interrupt  */
414 9fddaa0c bellard
    struct QEMUTimer *decr_timer;
415 47103572 j_mayer
    void *opaque;
416 9fddaa0c bellard
};
417 9fddaa0c bellard
418 9fddaa0c bellard
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
419 9fddaa0c bellard
{
420 9fddaa0c bellard
    /* TB time in tb periods */
421 9fddaa0c bellard
    return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
422 76a66253 j_mayer
                    tb_env->tb_freq, ticks_per_sec);
423 9fddaa0c bellard
}
424 9fddaa0c bellard
425 9fddaa0c bellard
uint32_t cpu_ppc_load_tbl (CPUState *env)
426 9fddaa0c bellard
{
427 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
428 9fddaa0c bellard
    uint64_t tb;
429 9fddaa0c bellard
430 9fddaa0c bellard
    tb = cpu_ppc_get_tb(tb_env);
431 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
432 9fddaa0c bellard
    {
433 76a66253 j_mayer
        static int last_time;
434 76a66253 j_mayer
        int now;
435 76a66253 j_mayer
        now = time(NULL);
436 76a66253 j_mayer
        if (last_time != now) {
437 76a66253 j_mayer
            last_time = now;
438 4b6d0a4c j_mayer
            if (loglevel != 0) {
439 a496775f j_mayer
                fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n",
440 a496775f j_mayer
                        __func__, tb, now, tb_env->tb_offset);
441 a496775f j_mayer
            }
442 76a66253 j_mayer
        }
443 9fddaa0c bellard
    }
444 9fddaa0c bellard
#endif
445 9fddaa0c bellard
446 9fddaa0c bellard
    return tb & 0xFFFFFFFF;
447 9fddaa0c bellard
}
448 9fddaa0c bellard
449 9fddaa0c bellard
uint32_t cpu_ppc_load_tbu (CPUState *env)
450 9fddaa0c bellard
{
451 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
452 9fddaa0c bellard
    uint64_t tb;
453 9fddaa0c bellard
454 9fddaa0c bellard
    tb = cpu_ppc_get_tb(tb_env);
455 4b6d0a4c j_mayer
#if defined(PPC_DEBUG_TB)
456 4b6d0a4c j_mayer
    if (loglevel != 0) {
457 a496775f j_mayer
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
458 a496775f j_mayer
    }
459 9fddaa0c bellard
#endif
460 76a66253 j_mayer
461 9fddaa0c bellard
    return tb >> 32;
462 9fddaa0c bellard
}
463 9fddaa0c bellard
464 9fddaa0c bellard
static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
465 9fddaa0c bellard
{
466 9fddaa0c bellard
    tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
467 9fddaa0c bellard
        - qemu_get_clock(vm_clock);
468 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
469 4b6d0a4c j_mayer
    if (loglevel != 0) {
470 4b6d0a4c j_mayer
        fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
471 4b6d0a4c j_mayer
                tb_env->tb_offset);
472 a496775f j_mayer
    }
473 9fddaa0c bellard
#endif
474 9fddaa0c bellard
}
475 9fddaa0c bellard
476 9fddaa0c bellard
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
477 9fddaa0c bellard
{
478 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
479 9fddaa0c bellard
480 9fddaa0c bellard
    cpu_ppc_store_tb(tb_env,
481 9fddaa0c bellard
                     ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
482 9fddaa0c bellard
}
483 9fddaa0c bellard
484 9fddaa0c bellard
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
485 9fddaa0c bellard
{
486 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
487 9fddaa0c bellard
488 9fddaa0c bellard
    cpu_ppc_store_tb(tb_env,
489 9fddaa0c bellard
                     ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
490 9fddaa0c bellard
}
491 9fddaa0c bellard
492 9fddaa0c bellard
uint32_t cpu_ppc_load_decr (CPUState *env)
493 9fddaa0c bellard
{
494 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
495 9fddaa0c bellard
    uint32_t decr;
496 4e588a4d bellard
    int64_t diff;
497 9fddaa0c bellard
498 4e588a4d bellard
    diff = tb_env->decr_next - qemu_get_clock(vm_clock);
499 4e588a4d bellard
    if (diff >= 0)
500 4e588a4d bellard
        decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
501 4e588a4d bellard
    else
502 4e588a4d bellard
        decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
503 4b6d0a4c j_mayer
#if defined(PPC_DEBUG_TB)
504 4b6d0a4c j_mayer
    if (loglevel != 0) {
505 a496775f j_mayer
        fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
506 a496775f j_mayer
    }
507 9fddaa0c bellard
#endif
508 76a66253 j_mayer
509 9fddaa0c bellard
    return decr;
510 9fddaa0c bellard
}
511 9fddaa0c bellard
512 9fddaa0c bellard
/* When decrementer expires,
513 9fddaa0c bellard
 * all we need to do is generate or queue a CPU exception
514 9fddaa0c bellard
 */
515 9fddaa0c bellard
static inline void cpu_ppc_decr_excp (CPUState *env)
516 9fddaa0c bellard
{
517 9fddaa0c bellard
    /* Raise it */
518 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
519 4b6d0a4c j_mayer
    if (loglevel != 0) {
520 a496775f j_mayer
        fprintf(logfile, "raise decrementer exception\n");
521 a496775f j_mayer
    }
522 9fddaa0c bellard
#endif
523 47103572 j_mayer
    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
524 9fddaa0c bellard
}
525 9fddaa0c bellard
526 9fddaa0c bellard
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
527 9fddaa0c bellard
                                 uint32_t value, int is_excp)
528 9fddaa0c bellard
{
529 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
530 9fddaa0c bellard
    uint64_t now, next;
531 9fddaa0c bellard
532 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
533 4b6d0a4c j_mayer
    if (loglevel != 0) {
534 a496775f j_mayer
        fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
535 a496775f j_mayer
    }
536 9fddaa0c bellard
#endif
537 9fddaa0c bellard
    now = qemu_get_clock(vm_clock);
538 9fddaa0c bellard
    next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
539 9fddaa0c bellard
    if (is_excp)
540 9fddaa0c bellard
        next += tb_env->decr_next - now;
541 9fddaa0c bellard
    if (next == now)
542 76a66253 j_mayer
        next++;
543 9fddaa0c bellard
    tb_env->decr_next = next;
544 9fddaa0c bellard
    /* Adjust timer */
545 9fddaa0c bellard
    qemu_mod_timer(tb_env->decr_timer, next);
546 9fddaa0c bellard
    /* If we set a negative value and the decrementer was positive,
547 9fddaa0c bellard
     * raise an exception.
548 9fddaa0c bellard
     */
549 9fddaa0c bellard
    if ((value & 0x80000000) && !(decr & 0x80000000))
550 76a66253 j_mayer
        cpu_ppc_decr_excp(env);
551 9fddaa0c bellard
}
552 9fddaa0c bellard
553 9fddaa0c bellard
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
554 9fddaa0c bellard
{
555 9fddaa0c bellard
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
556 9fddaa0c bellard
}
557 9fddaa0c bellard
558 9fddaa0c bellard
static void cpu_ppc_decr_cb (void *opaque)
559 9fddaa0c bellard
{
560 9fddaa0c bellard
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
561 9fddaa0c bellard
}
562 9fddaa0c bellard
563 8ecc7913 j_mayer
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
564 8ecc7913 j_mayer
{
565 8ecc7913 j_mayer
    CPUState *env = opaque;
566 8ecc7913 j_mayer
    ppc_tb_t *tb_env = env->tb_env;
567 8ecc7913 j_mayer
568 8ecc7913 j_mayer
    tb_env->tb_freq = freq;
569 8ecc7913 j_mayer
    /* There is a bug in Linux 2.4 kernels:
570 8ecc7913 j_mayer
     * if a decrementer exception is pending when it enables msr_ee at startup,
571 8ecc7913 j_mayer
     * it's not ready to handle it...
572 8ecc7913 j_mayer
     */
573 8ecc7913 j_mayer
    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
574 8ecc7913 j_mayer
}
575 8ecc7913 j_mayer
576 9fddaa0c bellard
/* Set up (once) timebase frequency (in Hz) */
577 8ecc7913 j_mayer
clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
578 9fddaa0c bellard
{
579 9fddaa0c bellard
    ppc_tb_t *tb_env;
580 9fddaa0c bellard
581 9fddaa0c bellard
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
582 9fddaa0c bellard
    if (tb_env == NULL)
583 9fddaa0c bellard
        return NULL;
584 9fddaa0c bellard
    env->tb_env = tb_env;
585 8ecc7913 j_mayer
    /* Create new timer */
586 8ecc7913 j_mayer
    tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
587 8ecc7913 j_mayer
    cpu_ppc_set_tb_clk(env, freq);
588 9fddaa0c bellard
589 8ecc7913 j_mayer
    return &cpu_ppc_set_tb_clk;
590 9fddaa0c bellard
}
591 9fddaa0c bellard
592 76a66253 j_mayer
/* Specific helpers for POWER & PowerPC 601 RTC */
593 8ecc7913 j_mayer
clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
594 76a66253 j_mayer
{
595 76a66253 j_mayer
    return cpu_ppc_tb_init(env, 7812500);
596 76a66253 j_mayer
}
597 76a66253 j_mayer
598 76a66253 j_mayer
void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
599 76a66253 j_mayer
__attribute__ (( alias ("cpu_ppc_store_tbu") ));
600 76a66253 j_mayer
601 76a66253 j_mayer
uint32_t cpu_ppc601_load_rtcu (CPUState *env)
602 76a66253 j_mayer
__attribute__ (( alias ("cpu_ppc_load_tbu") ));
603 76a66253 j_mayer
604 76a66253 j_mayer
void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
605 76a66253 j_mayer
{
606 76a66253 j_mayer
    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
607 76a66253 j_mayer
}
608 76a66253 j_mayer
609 76a66253 j_mayer
uint32_t cpu_ppc601_load_rtcl (CPUState *env)
610 76a66253 j_mayer
{
611 76a66253 j_mayer
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
612 76a66253 j_mayer
}
613 76a66253 j_mayer
614 636aaad7 j_mayer
/*****************************************************************************/
615 76a66253 j_mayer
/* Embedded PowerPC timers */
616 636aaad7 j_mayer
617 636aaad7 j_mayer
/* PIT, FIT & WDT */
618 636aaad7 j_mayer
typedef struct ppcemb_timer_t ppcemb_timer_t;
619 636aaad7 j_mayer
struct ppcemb_timer_t {
620 636aaad7 j_mayer
    uint64_t pit_reload;  /* PIT auto-reload value        */
621 636aaad7 j_mayer
    uint64_t fit_next;    /* Tick for next FIT interrupt  */
622 636aaad7 j_mayer
    struct QEMUTimer *fit_timer;
623 636aaad7 j_mayer
    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
624 636aaad7 j_mayer
    struct QEMUTimer *wdt_timer;
625 636aaad7 j_mayer
};
626 636aaad7 j_mayer
   
627 636aaad7 j_mayer
/* Fixed interval timer */
628 636aaad7 j_mayer
static void cpu_4xx_fit_cb (void *opaque)
629 636aaad7 j_mayer
{
630 636aaad7 j_mayer
    CPUState *env;
631 636aaad7 j_mayer
    ppc_tb_t *tb_env;
632 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
633 636aaad7 j_mayer
    uint64_t now, next;
634 636aaad7 j_mayer
635 636aaad7 j_mayer
    env = opaque;
636 636aaad7 j_mayer
    tb_env = env->tb_env;
637 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
638 636aaad7 j_mayer
    now = qemu_get_clock(vm_clock);
639 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
640 636aaad7 j_mayer
    case 0:
641 636aaad7 j_mayer
        next = 1 << 9;
642 636aaad7 j_mayer
        break;
643 636aaad7 j_mayer
    case 1:
644 636aaad7 j_mayer
        next = 1 << 13;
645 636aaad7 j_mayer
        break;
646 636aaad7 j_mayer
    case 2:
647 636aaad7 j_mayer
        next = 1 << 17;
648 636aaad7 j_mayer
        break;
649 636aaad7 j_mayer
    case 3:
650 636aaad7 j_mayer
        next = 1 << 21;
651 636aaad7 j_mayer
        break;
652 636aaad7 j_mayer
    default:
653 636aaad7 j_mayer
        /* Cannot occur, but makes gcc happy */
654 636aaad7 j_mayer
        return;
655 636aaad7 j_mayer
    }
656 636aaad7 j_mayer
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
657 636aaad7 j_mayer
    if (next == now)
658 636aaad7 j_mayer
        next++;
659 636aaad7 j_mayer
    qemu_mod_timer(ppcemb_timer->fit_timer, next);
660 636aaad7 j_mayer
    env->spr[SPR_40x_TSR] |= 1 << 26;
661 636aaad7 j_mayer
    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
662 636aaad7 j_mayer
        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
663 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
664 4b6d0a4c j_mayer
    if (loglevel != 0) {
665 e96efcfc j_mayer
        fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
666 e96efcfc j_mayer
                (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
667 636aaad7 j_mayer
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
668 636aaad7 j_mayer
    }
669 4b6d0a4c j_mayer
#endif
670 636aaad7 j_mayer
}
671 636aaad7 j_mayer
672 636aaad7 j_mayer
/* Programmable interval timer */
673 4b6d0a4c j_mayer
static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
674 76a66253 j_mayer
{
675 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
676 636aaad7 j_mayer
    uint64_t now, next;
677 636aaad7 j_mayer
678 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
679 4b6d0a4c j_mayer
    if (ppcemb_timer->pit_reload <= 1 ||
680 4b6d0a4c j_mayer
        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
681 4b6d0a4c j_mayer
        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
682 4b6d0a4c j_mayer
        /* Stop PIT */
683 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
684 4b6d0a4c j_mayer
        if (loglevel != 0) {
685 4b6d0a4c j_mayer
            fprintf(logfile, "%s: stop PIT\n", __func__);
686 4b6d0a4c j_mayer
        }
687 4b6d0a4c j_mayer
#endif
688 4b6d0a4c j_mayer
        qemu_del_timer(tb_env->decr_timer);
689 4b6d0a4c j_mayer
    } else {
690 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
691 4b6d0a4c j_mayer
        if (loglevel != 0) {
692 4b6d0a4c j_mayer
            fprintf(logfile, "%s: start PIT 0x" REGX "\n",
693 4b6d0a4c j_mayer
                    __func__, ppcemb_timer->pit_reload);
694 4b6d0a4c j_mayer
        }
695 4b6d0a4c j_mayer
#endif
696 4b6d0a4c j_mayer
        now = qemu_get_clock(vm_clock);
697 636aaad7 j_mayer
        next = now + muldiv64(ppcemb_timer->pit_reload,
698 636aaad7 j_mayer
                              ticks_per_sec, tb_env->tb_freq);
699 4b6d0a4c j_mayer
        if (is_excp)
700 4b6d0a4c j_mayer
            next += tb_env->decr_next - now;
701 636aaad7 j_mayer
        if (next == now)
702 636aaad7 j_mayer
            next++;
703 636aaad7 j_mayer
        qemu_mod_timer(tb_env->decr_timer, next);
704 636aaad7 j_mayer
        tb_env->decr_next = next;
705 636aaad7 j_mayer
    }
706 4b6d0a4c j_mayer
}
707 4b6d0a4c j_mayer
708 4b6d0a4c j_mayer
static void cpu_4xx_pit_cb (void *opaque)
709 4b6d0a4c j_mayer
{
710 4b6d0a4c j_mayer
    CPUState *env;
711 4b6d0a4c j_mayer
    ppc_tb_t *tb_env;
712 4b6d0a4c j_mayer
    ppcemb_timer_t *ppcemb_timer;
713 4b6d0a4c j_mayer
714 4b6d0a4c j_mayer
    env = opaque;
715 4b6d0a4c j_mayer
    tb_env = env->tb_env;
716 4b6d0a4c j_mayer
    ppcemb_timer = tb_env->opaque;
717 636aaad7 j_mayer
    env->spr[SPR_40x_TSR] |= 1 << 27;
718 636aaad7 j_mayer
    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
719 636aaad7 j_mayer
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
720 4b6d0a4c j_mayer
    start_stop_pit(env, tb_env, 1);
721 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
722 4b6d0a4c j_mayer
    if (loglevel != 0) {
723 e96efcfc j_mayer
        fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
724 e96efcfc j_mayer
                "%016" PRIx64 "\n", __func__,
725 e96efcfc j_mayer
                (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
726 e96efcfc j_mayer
                (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
727 636aaad7 j_mayer
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
728 636aaad7 j_mayer
                ppcemb_timer->pit_reload);
729 636aaad7 j_mayer
    }
730 4b6d0a4c j_mayer
#endif
731 636aaad7 j_mayer
}
732 636aaad7 j_mayer
733 636aaad7 j_mayer
/* Watchdog timer */
734 636aaad7 j_mayer
static void cpu_4xx_wdt_cb (void *opaque)
735 636aaad7 j_mayer
{
736 636aaad7 j_mayer
    CPUState *env;
737 636aaad7 j_mayer
    ppc_tb_t *tb_env;
738 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
739 636aaad7 j_mayer
    uint64_t now, next;
740 636aaad7 j_mayer
741 636aaad7 j_mayer
    env = opaque;
742 636aaad7 j_mayer
    tb_env = env->tb_env;
743 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
744 636aaad7 j_mayer
    now = qemu_get_clock(vm_clock);
745 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
746 636aaad7 j_mayer
    case 0:
747 636aaad7 j_mayer
        next = 1 << 17;
748 636aaad7 j_mayer
        break;
749 636aaad7 j_mayer
    case 1:
750 636aaad7 j_mayer
        next = 1 << 21;
751 636aaad7 j_mayer
        break;
752 636aaad7 j_mayer
    case 2:
753 636aaad7 j_mayer
        next = 1 << 25;
754 636aaad7 j_mayer
        break;
755 636aaad7 j_mayer
    case 3:
756 636aaad7 j_mayer
        next = 1 << 29;
757 636aaad7 j_mayer
        break;
758 636aaad7 j_mayer
    default:
759 636aaad7 j_mayer
        /* Cannot occur, but makes gcc happy */
760 636aaad7 j_mayer
        return;
761 636aaad7 j_mayer
    }
762 636aaad7 j_mayer
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
763 636aaad7 j_mayer
    if (next == now)
764 636aaad7 j_mayer
        next++;
765 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
766 4b6d0a4c j_mayer
    if (loglevel != 0) {
767 e96efcfc j_mayer
        fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
768 636aaad7 j_mayer
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
769 636aaad7 j_mayer
    }
770 4b6d0a4c j_mayer
#endif
771 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
772 636aaad7 j_mayer
    case 0x0:
773 636aaad7 j_mayer
    case 0x1:
774 636aaad7 j_mayer
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
775 636aaad7 j_mayer
        ppcemb_timer->wdt_next = next;
776 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= 1 << 31;
777 636aaad7 j_mayer
        break;
778 636aaad7 j_mayer
    case 0x2:
779 636aaad7 j_mayer
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
780 636aaad7 j_mayer
        ppcemb_timer->wdt_next = next;
781 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= 1 << 30;
782 636aaad7 j_mayer
        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
783 636aaad7 j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
784 636aaad7 j_mayer
        break;
785 636aaad7 j_mayer
    case 0x3:
786 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] &= ~0x30000000;
787 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
788 636aaad7 j_mayer
        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
789 636aaad7 j_mayer
        case 0x0:
790 636aaad7 j_mayer
            /* No reset */
791 636aaad7 j_mayer
            break;
792 636aaad7 j_mayer
        case 0x1: /* Core reset */
793 8ecc7913 j_mayer
            ppc40x_core_reset(env);
794 8ecc7913 j_mayer
            break;
795 636aaad7 j_mayer
        case 0x2: /* Chip reset */
796 8ecc7913 j_mayer
            ppc40x_chip_reset(env);
797 8ecc7913 j_mayer
            break;
798 636aaad7 j_mayer
        case 0x3: /* System reset */
799 8ecc7913 j_mayer
            ppc40x_system_reset(env);
800 8ecc7913 j_mayer
            break;
801 636aaad7 j_mayer
        }
802 636aaad7 j_mayer
    }
803 76a66253 j_mayer
}
804 76a66253 j_mayer
805 76a66253 j_mayer
void store_40x_pit (CPUState *env, target_ulong val)
806 76a66253 j_mayer
{
807 636aaad7 j_mayer
    ppc_tb_t *tb_env;
808 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
809 636aaad7 j_mayer
810 636aaad7 j_mayer
    tb_env = env->tb_env;
811 636aaad7 j_mayer
    ppcemb_timer = tb_env->opaque;
812 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
813 4b6d0a4c j_mayer
    if (loglevel != 0) {
814 636aaad7 j_mayer
        fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
815 a496775f j_mayer
    }
816 4b6d0a4c j_mayer
#endif
817 636aaad7 j_mayer
    ppcemb_timer->pit_reload = val;
818 4b6d0a4c j_mayer
    start_stop_pit(env, tb_env, 0);
819 76a66253 j_mayer
}
820 76a66253 j_mayer
821 636aaad7 j_mayer
target_ulong load_40x_pit (CPUState *env)
822 76a66253 j_mayer
{
823 636aaad7 j_mayer
    return cpu_ppc_load_decr(env);
824 76a66253 j_mayer
}
825 76a66253 j_mayer
826 76a66253 j_mayer
void store_booke_tsr (CPUState *env, target_ulong val)
827 76a66253 j_mayer
{
828 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
829 4b6d0a4c j_mayer
    if (loglevel != 0) {
830 4b6d0a4c j_mayer
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
831 4b6d0a4c j_mayer
    }
832 4b6d0a4c j_mayer
#endif
833 4b6d0a4c j_mayer
    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
834 4b6d0a4c j_mayer
    if (val & 0x80000000)
835 4b6d0a4c j_mayer
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
836 636aaad7 j_mayer
}
837 636aaad7 j_mayer
838 636aaad7 j_mayer
void store_booke_tcr (CPUState *env, target_ulong val)
839 636aaad7 j_mayer
{
840 4b6d0a4c j_mayer
    ppc_tb_t *tb_env;
841 4b6d0a4c j_mayer
842 4b6d0a4c j_mayer
    tb_env = env->tb_env;
843 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
844 4b6d0a4c j_mayer
    if (loglevel != 0) {
845 4b6d0a4c j_mayer
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
846 4b6d0a4c j_mayer
    }
847 4b6d0a4c j_mayer
#endif
848 4b6d0a4c j_mayer
    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
849 4b6d0a4c j_mayer
    start_stop_pit(env, tb_env, 1);
850 8ecc7913 j_mayer
    cpu_4xx_wdt_cb(env);
851 636aaad7 j_mayer
}
852 636aaad7 j_mayer
853 4b6d0a4c j_mayer
static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
854 4b6d0a4c j_mayer
{
855 4b6d0a4c j_mayer
    CPUState *env = opaque;
856 4b6d0a4c j_mayer
    ppc_tb_t *tb_env = env->tb_env;
857 4b6d0a4c j_mayer
858 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
859 4b6d0a4c j_mayer
    if (loglevel != 0) {
860 4b6d0a4c j_mayer
        fprintf(logfile, "%s set new frequency to %u\n", __func__, freq);
861 4b6d0a4c j_mayer
    }
862 4b6d0a4c j_mayer
#endif
863 4b6d0a4c j_mayer
    tb_env->tb_freq = freq;
864 4b6d0a4c j_mayer
    /* XXX: we should also update all timers */
865 4b6d0a4c j_mayer
}
866 4b6d0a4c j_mayer
867 8ecc7913 j_mayer
clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
868 636aaad7 j_mayer
{
869 636aaad7 j_mayer
    ppc_tb_t *tb_env;
870 636aaad7 j_mayer
    ppcemb_timer_t *ppcemb_timer;
871 636aaad7 j_mayer
872 8ecc7913 j_mayer
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
873 4b6d0a4c j_mayer
    if (tb_env == NULL) {
874 8ecc7913 j_mayer
        return NULL;
875 4b6d0a4c j_mayer
    }
876 8ecc7913 j_mayer
    env->tb_env = tb_env;
877 636aaad7 j_mayer
    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
878 8ecc7913 j_mayer
    tb_env->tb_freq = freq;
879 636aaad7 j_mayer
    tb_env->opaque = ppcemb_timer;
880 4b6d0a4c j_mayer
#ifdef PPC_DEBUG_TB
881 4b6d0a4c j_mayer
    if (loglevel != 0) {
882 4b6d0a4c j_mayer
        fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer,
883 4b6d0a4c j_mayer
                &ppc_emb_set_tb_clk);
884 8ecc7913 j_mayer
    }
885 4b6d0a4c j_mayer
#endif
886 636aaad7 j_mayer
    if (ppcemb_timer != NULL) {
887 636aaad7 j_mayer
        /* We use decr timer for PIT */
888 636aaad7 j_mayer
        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
889 636aaad7 j_mayer
        ppcemb_timer->fit_timer =
890 636aaad7 j_mayer
            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
891 636aaad7 j_mayer
        ppcemb_timer->wdt_timer =
892 636aaad7 j_mayer
            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
893 636aaad7 j_mayer
    }
894 8ecc7913 j_mayer
895 4b6d0a4c j_mayer
    return &ppc_emb_set_tb_clk;
896 76a66253 j_mayer
}
897 76a66253 j_mayer
898 2e719ba3 j_mayer
/*****************************************************************************/
899 2e719ba3 j_mayer
/* Embedded PowerPC Device Control Registers */
900 2e719ba3 j_mayer
typedef struct ppc_dcrn_t ppc_dcrn_t;
901 2e719ba3 j_mayer
struct ppc_dcrn_t {
902 2e719ba3 j_mayer
    dcr_read_cb dcr_read;
903 2e719ba3 j_mayer
    dcr_write_cb dcr_write;
904 2e719ba3 j_mayer
    void *opaque;
905 2e719ba3 j_mayer
};
906 2e719ba3 j_mayer
907 2e719ba3 j_mayer
#define DCRN_NB 1024
908 2e719ba3 j_mayer
struct ppc_dcr_t {
909 2e719ba3 j_mayer
    ppc_dcrn_t dcrn[DCRN_NB];
910 2e719ba3 j_mayer
    int (*read_error)(int dcrn);
911 2e719ba3 j_mayer
    int (*write_error)(int dcrn);
912 2e719ba3 j_mayer
};
913 2e719ba3 j_mayer
914 2e719ba3 j_mayer
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
915 2e719ba3 j_mayer
{
916 2e719ba3 j_mayer
    ppc_dcrn_t *dcr;
917 2e719ba3 j_mayer
918 2e719ba3 j_mayer
    if (dcrn < 0 || dcrn >= DCRN_NB)
919 2e719ba3 j_mayer
        goto error;
920 2e719ba3 j_mayer
    dcr = &dcr_env->dcrn[dcrn];
921 2e719ba3 j_mayer
    if (dcr->dcr_read == NULL)
922 2e719ba3 j_mayer
        goto error;
923 2e719ba3 j_mayer
    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
924 2e719ba3 j_mayer
925 2e719ba3 j_mayer
    return 0;
926 2e719ba3 j_mayer
927 2e719ba3 j_mayer
 error:
928 2e719ba3 j_mayer
    if (dcr_env->read_error != NULL)
929 2e719ba3 j_mayer
        return (*dcr_env->read_error)(dcrn);
930 2e719ba3 j_mayer
931 2e719ba3 j_mayer
    return -1;
932 2e719ba3 j_mayer
}
933 2e719ba3 j_mayer
934 2e719ba3 j_mayer
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
935 2e719ba3 j_mayer
{
936 2e719ba3 j_mayer
    ppc_dcrn_t *dcr;
937 2e719ba3 j_mayer
938 2e719ba3 j_mayer
    if (dcrn < 0 || dcrn >= DCRN_NB)
939 2e719ba3 j_mayer
        goto error;
940 2e719ba3 j_mayer
    dcr = &dcr_env->dcrn[dcrn];
941 2e719ba3 j_mayer
    if (dcr->dcr_write == NULL)
942 2e719ba3 j_mayer
        goto error;
943 2e719ba3 j_mayer
    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
944 2e719ba3 j_mayer
945 2e719ba3 j_mayer
    return 0;
946 2e719ba3 j_mayer
947 2e719ba3 j_mayer
 error:
948 2e719ba3 j_mayer
    if (dcr_env->write_error != NULL)
949 2e719ba3 j_mayer
        return (*dcr_env->write_error)(dcrn);
950 2e719ba3 j_mayer
951 2e719ba3 j_mayer
    return -1;
952 2e719ba3 j_mayer
}
953 2e719ba3 j_mayer
954 2e719ba3 j_mayer
int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
955 2e719ba3 j_mayer
                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
956 2e719ba3 j_mayer
{
957 2e719ba3 j_mayer
    ppc_dcr_t *dcr_env;
958 2e719ba3 j_mayer
    ppc_dcrn_t *dcr;
959 2e719ba3 j_mayer
960 2e719ba3 j_mayer
    dcr_env = env->dcr_env;
961 2e719ba3 j_mayer
    if (dcr_env == NULL)
962 2e719ba3 j_mayer
        return -1;
963 2e719ba3 j_mayer
    if (dcrn < 0 || dcrn >= DCRN_NB)
964 2e719ba3 j_mayer
        return -1;
965 2e719ba3 j_mayer
    dcr = &dcr_env->dcrn[dcrn];
966 2e719ba3 j_mayer
    if (dcr->opaque != NULL ||
967 2e719ba3 j_mayer
        dcr->dcr_read != NULL ||
968 2e719ba3 j_mayer
        dcr->dcr_write != NULL)
969 2e719ba3 j_mayer
        return -1;
970 2e719ba3 j_mayer
    dcr->opaque = opaque;
971 2e719ba3 j_mayer
    dcr->dcr_read = dcr_read;
972 2e719ba3 j_mayer
    dcr->dcr_write = dcr_write;
973 2e719ba3 j_mayer
974 2e719ba3 j_mayer
    return 0;
975 2e719ba3 j_mayer
}
976 2e719ba3 j_mayer
977 2e719ba3 j_mayer
int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
978 2e719ba3 j_mayer
                  int (*write_error)(int dcrn))
979 2e719ba3 j_mayer
{
980 2e719ba3 j_mayer
    ppc_dcr_t *dcr_env;
981 2e719ba3 j_mayer
982 2e719ba3 j_mayer
    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
983 2e719ba3 j_mayer
    if (dcr_env == NULL)
984 2e719ba3 j_mayer
        return -1;
985 2e719ba3 j_mayer
    dcr_env->read_error = read_error;
986 2e719ba3 j_mayer
    dcr_env->write_error = write_error;
987 2e719ba3 j_mayer
    env->dcr_env = dcr_env;
988 2e719ba3 j_mayer
989 2e719ba3 j_mayer
    return 0;
990 2e719ba3 j_mayer
}
991 2e719ba3 j_mayer
992 2e719ba3 j_mayer
993 9fddaa0c bellard
#if 0
994 9fddaa0c bellard
/*****************************************************************************/
995 9fddaa0c bellard
/* Handle system reset (for now, just stop emulation) */
996 9fddaa0c bellard
void cpu_ppc_reset (CPUState *env)
997 9fddaa0c bellard
{
998 9fddaa0c bellard
    printf("Reset asked... Stop emulation\n");
999 9fddaa0c bellard
    abort();
1000 9fddaa0c bellard
}
1001 9fddaa0c bellard
#endif
1002 9fddaa0c bellard
1003 64201201 bellard
/*****************************************************************************/
1004 64201201 bellard
/* Debug port */
1005 fd0bbb12 bellard
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
1006 64201201 bellard
{
1007 64201201 bellard
    addr &= 0xF;
1008 64201201 bellard
    switch (addr) {
1009 64201201 bellard
    case 0:
1010 64201201 bellard
        printf("%c", val);
1011 64201201 bellard
        break;
1012 64201201 bellard
    case 1:
1013 64201201 bellard
        printf("\n");
1014 64201201 bellard
        fflush(stdout);
1015 64201201 bellard
        break;
1016 64201201 bellard
    case 2:
1017 64201201 bellard
        printf("Set loglevel to %04x\n", val);
1018 fd0bbb12 bellard
        cpu_set_log(val | 0x100);
1019 64201201 bellard
        break;
1020 64201201 bellard
    }
1021 64201201 bellard
}
1022 64201201 bellard
1023 64201201 bellard
/*****************************************************************************/
1024 64201201 bellard
/* NVRAM helpers */
1025 64201201 bellard
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
1026 64201201 bellard
{
1027 819385c5 bellard
    m48t59_write(nvram, addr, value);
1028 64201201 bellard
}
1029 64201201 bellard
1030 64201201 bellard
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
1031 64201201 bellard
{
1032 819385c5 bellard
    return m48t59_read(nvram, addr);
1033 64201201 bellard
}
1034 64201201 bellard
1035 64201201 bellard
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
1036 64201201 bellard
{
1037 819385c5 bellard
    m48t59_write(nvram, addr, value >> 8);
1038 819385c5 bellard
    m48t59_write(nvram, addr + 1, value & 0xFF);
1039 64201201 bellard
}
1040 64201201 bellard
1041 64201201 bellard
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
1042 64201201 bellard
{
1043 64201201 bellard
    uint16_t tmp;
1044 64201201 bellard
1045 819385c5 bellard
    tmp = m48t59_read(nvram, addr) << 8;
1046 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 1);
1047 64201201 bellard
    return tmp;
1048 64201201 bellard
}
1049 64201201 bellard
1050 64201201 bellard
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
1051 64201201 bellard
{
1052 819385c5 bellard
    m48t59_write(nvram, addr, value >> 24);
1053 819385c5 bellard
    m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
1054 819385c5 bellard
    m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
1055 819385c5 bellard
    m48t59_write(nvram, addr + 3, value & 0xFF);
1056 64201201 bellard
}
1057 64201201 bellard
1058 64201201 bellard
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
1059 64201201 bellard
{
1060 64201201 bellard
    uint32_t tmp;
1061 64201201 bellard
1062 819385c5 bellard
    tmp = m48t59_read(nvram, addr) << 24;
1063 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 1) << 16;
1064 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 2) << 8;
1065 819385c5 bellard
    tmp |= m48t59_read(nvram, addr + 3);
1066 76a66253 j_mayer
1067 64201201 bellard
    return tmp;
1068 64201201 bellard
}
1069 64201201 bellard
1070 64201201 bellard
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
1071 64201201 bellard
                       const unsigned char *str, uint32_t max)
1072 64201201 bellard
{
1073 64201201 bellard
    int i;
1074 64201201 bellard
1075 64201201 bellard
    for (i = 0; i < max && str[i] != '\0'; i++) {
1076 819385c5 bellard
        m48t59_write(nvram, addr + i, str[i]);
1077 64201201 bellard
    }
1078 819385c5 bellard
    m48t59_write(nvram, addr + max - 1, '\0');
1079 64201201 bellard
}
1080 64201201 bellard
1081 64201201 bellard
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
1082 64201201 bellard
{
1083 64201201 bellard
    int i;
1084 64201201 bellard
1085 64201201 bellard
    memset(dst, 0, max);
1086 64201201 bellard
    for (i = 0; i < max; i++) {
1087 64201201 bellard
        dst[i] = NVRAM_get_byte(nvram, addr + i);
1088 64201201 bellard
        if (dst[i] == '\0')
1089 64201201 bellard
            break;
1090 64201201 bellard
    }
1091 64201201 bellard
1092 64201201 bellard
    return i;
1093 64201201 bellard
}
1094 64201201 bellard
1095 64201201 bellard
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1096 64201201 bellard
{
1097 64201201 bellard
    uint16_t tmp;
1098 64201201 bellard
    uint16_t pd, pd1, pd2;
1099 64201201 bellard
1100 64201201 bellard
    tmp = prev >> 8;
1101 64201201 bellard
    pd = prev ^ value;
1102 64201201 bellard
    pd1 = pd & 0x000F;
1103 64201201 bellard
    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1104 64201201 bellard
    tmp ^= (pd1 << 3) | (pd1 << 8);
1105 64201201 bellard
    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1106 64201201 bellard
1107 64201201 bellard
    return tmp;
1108 64201201 bellard
}
1109 64201201 bellard
1110 64201201 bellard
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
1111 64201201 bellard
{
1112 64201201 bellard
    uint32_t i;
1113 64201201 bellard
    uint16_t crc = 0xFFFF;
1114 64201201 bellard
    int odd;
1115 64201201 bellard
1116 64201201 bellard
    odd = count & 1;
1117 64201201 bellard
    count &= ~1;
1118 64201201 bellard
    for (i = 0; i != count; i++) {
1119 76a66253 j_mayer
        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1120 64201201 bellard
    }
1121 64201201 bellard
    if (odd) {
1122 76a66253 j_mayer
        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1123 64201201 bellard
    }
1124 64201201 bellard
1125 64201201 bellard
    return crc;
1126 64201201 bellard
}
1127 64201201 bellard
1128 fd0bbb12 bellard
#define CMDLINE_ADDR 0x017ff000
1129 fd0bbb12 bellard
1130 64201201 bellard
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
1131 64201201 bellard
                          const unsigned char *arch,
1132 64201201 bellard
                          uint32_t RAM_size, int boot_device,
1133 64201201 bellard
                          uint32_t kernel_image, uint32_t kernel_size,
1134 fd0bbb12 bellard
                          const char *cmdline,
1135 64201201 bellard
                          uint32_t initrd_image, uint32_t initrd_size,
1136 fd0bbb12 bellard
                          uint32_t NVRAM_image,
1137 fd0bbb12 bellard
                          int width, int height, int depth)
1138 64201201 bellard
{
1139 64201201 bellard
    uint16_t crc;
1140 64201201 bellard
1141 64201201 bellard
    /* Set parameters for Open Hack'Ware BIOS */
1142 64201201 bellard
    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1143 64201201 bellard
    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
1144 64201201 bellard
    NVRAM_set_word(nvram,   0x14, NVRAM_size);
1145 64201201 bellard
    NVRAM_set_string(nvram, 0x20, arch, 16);
1146 64201201 bellard
    NVRAM_set_lword(nvram,  0x30, RAM_size);
1147 64201201 bellard
    NVRAM_set_byte(nvram,   0x34, boot_device);
1148 64201201 bellard
    NVRAM_set_lword(nvram,  0x38, kernel_image);
1149 64201201 bellard
    NVRAM_set_lword(nvram,  0x3C, kernel_size);
1150 fd0bbb12 bellard
    if (cmdline) {
1151 fd0bbb12 bellard
        /* XXX: put the cmdline in NVRAM too ? */
1152 fd0bbb12 bellard
        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
1153 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
1154 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
1155 fd0bbb12 bellard
    } else {
1156 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x40, 0);
1157 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x44, 0);
1158 fd0bbb12 bellard
    }
1159 64201201 bellard
    NVRAM_set_lword(nvram,  0x48, initrd_image);
1160 64201201 bellard
    NVRAM_set_lword(nvram,  0x4C, initrd_size);
1161 64201201 bellard
    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
1162 fd0bbb12 bellard
1163 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x54, width);
1164 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x56, height);
1165 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x58, depth);
1166 fd0bbb12 bellard
    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1167 fd0bbb12 bellard
    NVRAM_set_word(nvram,  0xFC, crc);
1168 64201201 bellard
1169 64201201 bellard
    return 0;
1170 a541f297 bellard
}