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