Commit 008ff9d756fb8e33e7a799e47d03faac503f8b2e
1 parent
115646b6
Share devices that might be useful for all PowerPC 40x & 440 implementations
(mostly CPU registration and UIC, for now). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3340 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
587 additions
and
525 deletions
hw/ppc405.h
... | ... | @@ -25,6 +25,8 @@ |
25 | 25 | #if !defined(PPC_405_H) |
26 | 26 | #define PPC_405_H |
27 | 27 | |
28 | +#include "ppc4xx.h" | |
29 | + | |
28 | 30 | /* Bootinfo as set-up by u-boot */ |
29 | 31 | typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; |
30 | 32 | struct ppc4xx_bd_info_t { |
... | ... | @@ -54,19 +56,9 @@ struct ppc4xx_bd_info_t { |
54 | 56 | }; |
55 | 57 | |
56 | 58 | /* PowerPC 405 core */ |
57 | -CPUState *ppc405_init (const unsigned char *cpu_model, | |
58 | - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, | |
59 | - uint32_t sysclk); | |
60 | 59 | ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, |
61 | 60 | uint32_t flags); |
62 | 61 | |
63 | -/* */ | |
64 | -typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; | |
65 | -int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, | |
66 | - target_phys_addr_t offset, uint32_t len, | |
67 | - CPUReadMemoryFunc **mem_read, | |
68 | - CPUWriteMemoryFunc **mem_write, void *opaque); | |
69 | -ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base); | |
70 | 62 | /* PowerPC 4xx peripheral local bus arbitrer */ |
71 | 63 | void ppc4xx_plb_init (CPUState *env); |
72 | 64 | /* PLB to OPB bridge */ |
... | ... | @@ -74,14 +66,6 @@ void ppc4xx_pob_init (CPUState *env); |
74 | 66 | /* OPB arbitrer */ |
75 | 67 | void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, |
76 | 68 | target_phys_addr_t offset); |
77 | -/* PowerPC 4xx universal interrupt controller */ | |
78 | -enum { | |
79 | - PPCUIC_OUTPUT_INT = 0, | |
80 | - PPCUIC_OUTPUT_CINT = 1, | |
81 | - PPCUIC_OUTPUT_NB, | |
82 | -}; | |
83 | -qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, | |
84 | - uint32_t dcr_base, int has_ssr, int has_vr); | |
85 | 69 | /* SDRAM controller */ |
86 | 70 | void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, |
87 | 71 | target_phys_addr_t *ram_bases, | ... | ... |
hw/ppc405_uc.c
... | ... | @@ -27,7 +27,6 @@ |
27 | 27 | extern int loglevel; |
28 | 28 | extern FILE *logfile; |
29 | 29 | |
30 | -//#define DEBUG_MMIO | |
31 | 30 | #define DEBUG_OPBA |
32 | 31 | #define DEBUG_SDRAM |
33 | 32 | #define DEBUG_GPIO |
... | ... | @@ -36,41 +35,9 @@ extern FILE *logfile; |
36 | 35 | //#define DEBUG_I2C |
37 | 36 | #define DEBUG_GPT |
38 | 37 | #define DEBUG_MAL |
39 | -#define DEBUG_UIC | |
40 | 38 | #define DEBUG_CLOCKS |
41 | 39 | //#define DEBUG_UNASSIGNED |
42 | 40 | |
43 | -/*****************************************************************************/ | |
44 | -/* Generic PowerPC 405 processor instanciation */ | |
45 | -CPUState *ppc405_init (const unsigned char *cpu_model, | |
46 | - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, | |
47 | - uint32_t sysclk) | |
48 | -{ | |
49 | - CPUState *env; | |
50 | - ppc_def_t *def; | |
51 | - | |
52 | - /* init CPUs */ | |
53 | - env = cpu_init(); | |
54 | - ppc_find_by_name(cpu_model, &def); | |
55 | - if (def == NULL) { | |
56 | - cpu_abort(env, "Unable to find PowerPC %s CPU definition\n", | |
57 | - cpu_model); | |
58 | - } | |
59 | - cpu_ppc_register(env, def); | |
60 | - cpu_ppc_reset(env); | |
61 | - cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ | |
62 | - cpu_clk->opaque = env; | |
63 | - /* Set time-base frequency to sysclk */ | |
64 | - tb_clk->cb = ppc_emb_timers_init(env, sysclk); | |
65 | - tb_clk->opaque = env; | |
66 | - ppc_dcr_init(env, NULL, NULL); | |
67 | - /* Register Qemu callbacks */ | |
68 | - qemu_register_reset(&cpu_ppc_reset, env); | |
69 | - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); | |
70 | - | |
71 | - return env; | |
72 | -} | |
73 | - | |
74 | 41 | ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, |
75 | 42 | uint32_t flags) |
76 | 43 | { |
... | ... | @@ -124,203 +91,6 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, |
124 | 91 | /* Shared peripherals */ |
125 | 92 | |
126 | 93 | /*****************************************************************************/ |
127 | -/* Fake device used to map multiple devices in a single memory page */ | |
128 | -#define MMIO_AREA_BITS 8 | |
129 | -#define MMIO_AREA_LEN (1 << MMIO_AREA_BITS) | |
130 | -#define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) | |
131 | -#define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) | |
132 | -struct ppc4xx_mmio_t { | |
133 | - target_phys_addr_t base; | |
134 | - CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; | |
135 | - CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; | |
136 | - void *opaque[MMIO_AREA_NB]; | |
137 | -}; | |
138 | - | |
139 | -static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr) | |
140 | -{ | |
141 | -#ifdef DEBUG_UNASSIGNED | |
142 | - ppc4xx_mmio_t *mmio; | |
143 | - | |
144 | - mmio = opaque; | |
145 | - printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n", | |
146 | - addr, mmio->base); | |
147 | -#endif | |
148 | - | |
149 | - return 0; | |
150 | -} | |
151 | - | |
152 | -static void unassigned_mmio_writeb (void *opaque, | |
153 | - target_phys_addr_t addr, uint32_t val) | |
154 | -{ | |
155 | -#ifdef DEBUG_UNASSIGNED | |
156 | - ppc4xx_mmio_t *mmio; | |
157 | - | |
158 | - mmio = opaque; | |
159 | - printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n", | |
160 | - addr, val, mmio->base); | |
161 | -#endif | |
162 | -} | |
163 | - | |
164 | -static CPUReadMemoryFunc *unassigned_mmio_read[3] = { | |
165 | - unassigned_mmio_readb, | |
166 | - unassigned_mmio_readb, | |
167 | - unassigned_mmio_readb, | |
168 | -}; | |
169 | - | |
170 | -static CPUWriteMemoryFunc *unassigned_mmio_write[3] = { | |
171 | - unassigned_mmio_writeb, | |
172 | - unassigned_mmio_writeb, | |
173 | - unassigned_mmio_writeb, | |
174 | -}; | |
175 | - | |
176 | -static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, | |
177 | - target_phys_addr_t addr, int len) | |
178 | -{ | |
179 | - CPUReadMemoryFunc **mem_read; | |
180 | - uint32_t ret; | |
181 | - int idx; | |
182 | - | |
183 | - idx = MMIO_IDX(addr - mmio->base); | |
184 | -#if defined(DEBUG_MMIO) | |
185 | - printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__, | |
186 | - mmio, len, addr, idx); | |
187 | -#endif | |
188 | - mem_read = mmio->mem_read[idx]; | |
189 | - ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base); | |
190 | - | |
191 | - return ret; | |
192 | -} | |
193 | - | |
194 | -static void mmio_writelen (ppc4xx_mmio_t *mmio, | |
195 | - target_phys_addr_t addr, uint32_t value, int len) | |
196 | -{ | |
197 | - CPUWriteMemoryFunc **mem_write; | |
198 | - int idx; | |
199 | - | |
200 | - idx = MMIO_IDX(addr - mmio->base); | |
201 | -#if defined(DEBUG_MMIO) | |
202 | - printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__, | |
203 | - mmio, len, addr, idx, value); | |
204 | -#endif | |
205 | - mem_write = mmio->mem_write[idx]; | |
206 | - (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value); | |
207 | -} | |
208 | - | |
209 | -static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) | |
210 | -{ | |
211 | -#if defined(DEBUG_MMIO) | |
212 | - printf("%s: addr " PADDRX "\n", __func__, addr); | |
213 | -#endif | |
214 | - | |
215 | - return mmio_readlen(opaque, addr, 0); | |
216 | -} | |
217 | - | |
218 | -static void mmio_writeb (void *opaque, | |
219 | - target_phys_addr_t addr, uint32_t value) | |
220 | -{ | |
221 | -#if defined(DEBUG_MMIO) | |
222 | - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); | |
223 | -#endif | |
224 | - mmio_writelen(opaque, addr, value, 0); | |
225 | -} | |
226 | - | |
227 | -static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr) | |
228 | -{ | |
229 | -#if defined(DEBUG_MMIO) | |
230 | - printf("%s: addr " PADDRX "\n", __func__, addr); | |
231 | -#endif | |
232 | - | |
233 | - return mmio_readlen(opaque, addr, 1); | |
234 | -} | |
235 | - | |
236 | -static void mmio_writew (void *opaque, | |
237 | - target_phys_addr_t addr, uint32_t value) | |
238 | -{ | |
239 | -#if defined(DEBUG_MMIO) | |
240 | - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); | |
241 | -#endif | |
242 | - mmio_writelen(opaque, addr, value, 1); | |
243 | -} | |
244 | - | |
245 | -static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr) | |
246 | -{ | |
247 | -#if defined(DEBUG_MMIO) | |
248 | - printf("%s: addr " PADDRX "\n", __func__, addr); | |
249 | -#endif | |
250 | - | |
251 | - return mmio_readlen(opaque, addr, 2); | |
252 | -} | |
253 | - | |
254 | -static void mmio_writel (void *opaque, | |
255 | - target_phys_addr_t addr, uint32_t value) | |
256 | -{ | |
257 | -#if defined(DEBUG_MMIO) | |
258 | - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); | |
259 | -#endif | |
260 | - mmio_writelen(opaque, addr, value, 2); | |
261 | -} | |
262 | - | |
263 | -static CPUReadMemoryFunc *mmio_read[] = { | |
264 | - &mmio_readb, | |
265 | - &mmio_readw, | |
266 | - &mmio_readl, | |
267 | -}; | |
268 | - | |
269 | -static CPUWriteMemoryFunc *mmio_write[] = { | |
270 | - &mmio_writeb, | |
271 | - &mmio_writew, | |
272 | - &mmio_writel, | |
273 | -}; | |
274 | - | |
275 | -int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, | |
276 | - target_phys_addr_t offset, uint32_t len, | |
277 | - CPUReadMemoryFunc **mem_read, | |
278 | - CPUWriteMemoryFunc **mem_write, void *opaque) | |
279 | -{ | |
280 | - uint32_t end; | |
281 | - int idx, eidx; | |
282 | - | |
283 | - if ((offset + len) > TARGET_PAGE_SIZE) | |
284 | - return -1; | |
285 | - idx = MMIO_IDX(offset); | |
286 | - end = offset + len - 1; | |
287 | - eidx = MMIO_IDX(end); | |
288 | -#if defined(DEBUG_MMIO) | |
289 | - printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len, | |
290 | - end, idx, eidx); | |
291 | -#endif | |
292 | - for (; idx <= eidx; idx++) { | |
293 | - mmio->mem_read[idx] = mem_read; | |
294 | - mmio->mem_write[idx] = mem_write; | |
295 | - mmio->opaque[idx] = opaque; | |
296 | - } | |
297 | - | |
298 | - return 0; | |
299 | -} | |
300 | - | |
301 | -ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) | |
302 | -{ | |
303 | - ppc4xx_mmio_t *mmio; | |
304 | - int mmio_memory; | |
305 | - | |
306 | - mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); | |
307 | - if (mmio != NULL) { | |
308 | - mmio->base = base; | |
309 | - mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); | |
310 | -#if defined(DEBUG_MMIO) | |
311 | - printf("%s: %p base %08x len %08x %d\n", __func__, | |
312 | - mmio, base, TARGET_PAGE_SIZE, mmio_memory); | |
313 | -#endif | |
314 | - cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); | |
315 | - ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, | |
316 | - unassigned_mmio_read, unassigned_mmio_write, | |
317 | - mmio); | |
318 | - } | |
319 | - | |
320 | - return mmio; | |
321 | -} | |
322 | - | |
323 | -/*****************************************************************************/ | |
324 | 94 | /* Peripheral local bus arbitrer */ |
325 | 95 | enum { |
326 | 96 | PLB0_BESR = 0x084, |
... | ... | @@ -625,281 +395,6 @@ void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, |
625 | 395 | } |
626 | 396 | |
627 | 397 | /*****************************************************************************/ |
628 | -/* "Universal" Interrupt controller */ | |
629 | -enum { | |
630 | - DCR_UICSR = 0x000, | |
631 | - DCR_UICSRS = 0x001, | |
632 | - DCR_UICER = 0x002, | |
633 | - DCR_UICCR = 0x003, | |
634 | - DCR_UICPR = 0x004, | |
635 | - DCR_UICTR = 0x005, | |
636 | - DCR_UICMSR = 0x006, | |
637 | - DCR_UICVR = 0x007, | |
638 | - DCR_UICVCR = 0x008, | |
639 | - DCR_UICMAX = 0x009, | |
640 | -}; | |
641 | - | |
642 | -#define UIC_MAX_IRQ 32 | |
643 | -typedef struct ppcuic_t ppcuic_t; | |
644 | -struct ppcuic_t { | |
645 | - uint32_t dcr_base; | |
646 | - int use_vectors; | |
647 | - uint32_t uicsr; /* Status register */ | |
648 | - uint32_t uicer; /* Enable register */ | |
649 | - uint32_t uiccr; /* Critical register */ | |
650 | - uint32_t uicpr; /* Polarity register */ | |
651 | - uint32_t uictr; /* Triggering register */ | |
652 | - uint32_t uicvcr; /* Vector configuration register */ | |
653 | - uint32_t uicvr; | |
654 | - qemu_irq *irqs; | |
655 | -}; | |
656 | - | |
657 | -static void ppcuic_trigger_irq (ppcuic_t *uic) | |
658 | -{ | |
659 | - uint32_t ir, cr; | |
660 | - int start, end, inc, i; | |
661 | - | |
662 | - /* Trigger interrupt if any is pending */ | |
663 | - ir = uic->uicsr & uic->uicer & (~uic->uiccr); | |
664 | - cr = uic->uicsr & uic->uicer & uic->uiccr; | |
665 | -#ifdef DEBUG_UIC | |
666 | - if (loglevel & CPU_LOG_INT) { | |
667 | - fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n" | |
668 | - " %08x ir %08x cr %08x\n", __func__, | |
669 | - uic->uicsr, uic->uicer, uic->uiccr, | |
670 | - uic->uicsr & uic->uicer, ir, cr); | |
671 | - } | |
672 | -#endif | |
673 | - if (ir != 0x0000000) { | |
674 | -#ifdef DEBUG_UIC | |
675 | - if (loglevel & CPU_LOG_INT) { | |
676 | - fprintf(logfile, "Raise UIC interrupt\n"); | |
677 | - } | |
678 | -#endif | |
679 | - qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); | |
680 | - } else { | |
681 | -#ifdef DEBUG_UIC | |
682 | - if (loglevel & CPU_LOG_INT) { | |
683 | - fprintf(logfile, "Lower UIC interrupt\n"); | |
684 | - } | |
685 | -#endif | |
686 | - qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); | |
687 | - } | |
688 | - /* Trigger critical interrupt if any is pending and update vector */ | |
689 | - if (cr != 0x0000000) { | |
690 | - qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); | |
691 | - if (uic->use_vectors) { | |
692 | - /* Compute critical IRQ vector */ | |
693 | - if (uic->uicvcr & 1) { | |
694 | - start = 31; | |
695 | - end = 0; | |
696 | - inc = -1; | |
697 | - } else { | |
698 | - start = 0; | |
699 | - end = 31; | |
700 | - inc = 1; | |
701 | - } | |
702 | - uic->uicvr = uic->uicvcr & 0xFFFFFFFC; | |
703 | - for (i = start; i <= end; i += inc) { | |
704 | - if (cr & (1 << i)) { | |
705 | - uic->uicvr += (i - start) * 512 * inc; | |
706 | - break; | |
707 | - } | |
708 | - } | |
709 | - } | |
710 | -#ifdef DEBUG_UIC | |
711 | - if (loglevel & CPU_LOG_INT) { | |
712 | - fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n", | |
713 | - uic->uicvr); | |
714 | - } | |
715 | -#endif | |
716 | - } else { | |
717 | -#ifdef DEBUG_UIC | |
718 | - if (loglevel & CPU_LOG_INT) { | |
719 | - fprintf(logfile, "Lower UIC critical interrupt\n"); | |
720 | - } | |
721 | -#endif | |
722 | - qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); | |
723 | - uic->uicvr = 0x00000000; | |
724 | - } | |
725 | -} | |
726 | - | |
727 | -static void ppcuic_set_irq (void *opaque, int irq_num, int level) | |
728 | -{ | |
729 | - ppcuic_t *uic; | |
730 | - uint32_t mask, sr; | |
731 | - | |
732 | - uic = opaque; | |
733 | - mask = 1 << irq_num; | |
734 | -#ifdef DEBUG_UIC | |
735 | - if (loglevel & CPU_LOG_INT) { | |
736 | - fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x " | |
737 | - "%08x\n", __func__, irq_num, level, | |
738 | - uic->uicsr, mask, uic->uicsr & mask, level << irq_num); | |
739 | - } | |
740 | -#endif | |
741 | - if (irq_num < 0 || irq_num > 31) | |
742 | - return; | |
743 | - sr = uic->uicsr; | |
744 | - if (!(uic->uicpr & mask)) { | |
745 | - /* Negatively asserted IRQ */ | |
746 | - level = level == 0 ? 1 : 0; | |
747 | - } | |
748 | - /* Update status register */ | |
749 | - if (uic->uictr & mask) { | |
750 | - /* Edge sensitive interrupt */ | |
751 | - if (level == 1) | |
752 | - uic->uicsr |= mask; | |
753 | - } else { | |
754 | - /* Level sensitive interrupt */ | |
755 | - if (level == 1) | |
756 | - uic->uicsr |= mask; | |
757 | - else | |
758 | - uic->uicsr &= ~mask; | |
759 | - } | |
760 | -#ifdef DEBUG_UIC | |
761 | - if (loglevel & CPU_LOG_INT) { | |
762 | - fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__, | |
763 | - irq_num, level, uic->uicsr, sr); | |
764 | - } | |
765 | -#endif | |
766 | - if (sr != uic->uicsr) | |
767 | - ppcuic_trigger_irq(uic); | |
768 | -} | |
769 | - | |
770 | -static target_ulong dcr_read_uic (void *opaque, int dcrn) | |
771 | -{ | |
772 | - ppcuic_t *uic; | |
773 | - target_ulong ret; | |
774 | - | |
775 | - uic = opaque; | |
776 | - dcrn -= uic->dcr_base; | |
777 | - switch (dcrn) { | |
778 | - case DCR_UICSR: | |
779 | - case DCR_UICSRS: | |
780 | - ret = uic->uicsr; | |
781 | - break; | |
782 | - case DCR_UICER: | |
783 | - ret = uic->uicer; | |
784 | - break; | |
785 | - case DCR_UICCR: | |
786 | - ret = uic->uiccr; | |
787 | - break; | |
788 | - case DCR_UICPR: | |
789 | - ret = uic->uicpr; | |
790 | - break; | |
791 | - case DCR_UICTR: | |
792 | - ret = uic->uictr; | |
793 | - break; | |
794 | - case DCR_UICMSR: | |
795 | - ret = uic->uicsr & uic->uicer; | |
796 | - break; | |
797 | - case DCR_UICVR: | |
798 | - if (!uic->use_vectors) | |
799 | - goto no_read; | |
800 | - ret = uic->uicvr; | |
801 | - break; | |
802 | - case DCR_UICVCR: | |
803 | - if (!uic->use_vectors) | |
804 | - goto no_read; | |
805 | - ret = uic->uicvcr; | |
806 | - break; | |
807 | - default: | |
808 | - no_read: | |
809 | - ret = 0x00000000; | |
810 | - break; | |
811 | - } | |
812 | - | |
813 | - return ret; | |
814 | -} | |
815 | - | |
816 | -static void dcr_write_uic (void *opaque, int dcrn, target_ulong val) | |
817 | -{ | |
818 | - ppcuic_t *uic; | |
819 | - | |
820 | - uic = opaque; | |
821 | - dcrn -= uic->dcr_base; | |
822 | -#ifdef DEBUG_UIC | |
823 | - if (loglevel & CPU_LOG_INT) { | |
824 | - fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val); | |
825 | - } | |
826 | -#endif | |
827 | - switch (dcrn) { | |
828 | - case DCR_UICSR: | |
829 | - uic->uicsr &= ~val; | |
830 | - ppcuic_trigger_irq(uic); | |
831 | - break; | |
832 | - case DCR_UICSRS: | |
833 | - uic->uicsr |= val; | |
834 | - ppcuic_trigger_irq(uic); | |
835 | - break; | |
836 | - case DCR_UICER: | |
837 | - uic->uicer = val; | |
838 | - ppcuic_trigger_irq(uic); | |
839 | - break; | |
840 | - case DCR_UICCR: | |
841 | - uic->uiccr = val; | |
842 | - ppcuic_trigger_irq(uic); | |
843 | - break; | |
844 | - case DCR_UICPR: | |
845 | - uic->uicpr = val; | |
846 | - ppcuic_trigger_irq(uic); | |
847 | - break; | |
848 | - case DCR_UICTR: | |
849 | - uic->uictr = val; | |
850 | - ppcuic_trigger_irq(uic); | |
851 | - break; | |
852 | - case DCR_UICMSR: | |
853 | - break; | |
854 | - case DCR_UICVR: | |
855 | - break; | |
856 | - case DCR_UICVCR: | |
857 | - uic->uicvcr = val & 0xFFFFFFFD; | |
858 | - ppcuic_trigger_irq(uic); | |
859 | - break; | |
860 | - } | |
861 | -} | |
862 | - | |
863 | -static void ppcuic_reset (void *opaque) | |
864 | -{ | |
865 | - ppcuic_t *uic; | |
866 | - | |
867 | - uic = opaque; | |
868 | - uic->uiccr = 0x00000000; | |
869 | - uic->uicer = 0x00000000; | |
870 | - uic->uicpr = 0x00000000; | |
871 | - uic->uicsr = 0x00000000; | |
872 | - uic->uictr = 0x00000000; | |
873 | - if (uic->use_vectors) { | |
874 | - uic->uicvcr = 0x00000000; | |
875 | - uic->uicvr = 0x0000000; | |
876 | - } | |
877 | -} | |
878 | - | |
879 | -qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, | |
880 | - uint32_t dcr_base, int has_ssr, int has_vr) | |
881 | -{ | |
882 | - ppcuic_t *uic; | |
883 | - int i; | |
884 | - | |
885 | - uic = qemu_mallocz(sizeof(ppcuic_t)); | |
886 | - if (uic != NULL) { | |
887 | - uic->dcr_base = dcr_base; | |
888 | - uic->irqs = irqs; | |
889 | - if (has_vr) | |
890 | - uic->use_vectors = 1; | |
891 | - for (i = 0; i < DCR_UICMAX; i++) { | |
892 | - ppc_dcr_register(env, dcr_base + i, uic, | |
893 | - &dcr_read_uic, &dcr_write_uic); | |
894 | - } | |
895 | - qemu_register_reset(ppcuic_reset, uic); | |
896 | - ppcuic_reset(uic); | |
897 | - } | |
898 | - | |
899 | - return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); | |
900 | -} | |
901 | - | |
902 | -/*****************************************************************************/ | |
903 | 398 | /* Code decompression controller */ |
904 | 399 | /* XXX: TODO */ |
905 | 400 | |
... | ... | @@ -3040,7 +2535,7 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4], |
3040 | 2535 | int i; |
3041 | 2536 | |
3042 | 2537 | memset(clk_setup, 0, sizeof(clk_setup)); |
3043 | - env = ppc405_init("405cr", &clk_setup[PPC405CR_CPU_CLK], | |
2538 | + env = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], | |
3044 | 2539 | &clk_setup[PPC405CR_TMR_CLK], sysclk); |
3045 | 2540 | /* Memory mapped devices registers */ |
3046 | 2541 | mmio = ppc4xx_mmio_init(env, 0xEF600000); |
... | ... | @@ -3390,7 +2885,7 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2], |
3390 | 2885 | |
3391 | 2886 | memset(clk_setup, 0, sizeof(clk_setup)); |
3392 | 2887 | /* init CPUs */ |
3393 | - env = ppc405_init("405ep", &clk_setup[PPC405EP_CPU_CLK], | |
2888 | + env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], | |
3394 | 2889 | &tlb_clk_setup, sysclk); |
3395 | 2890 | clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; |
3396 | 2891 | clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; | ... | ... |
hw/ppc4xx.h
0 โ 100644
1 | +/* | |
2 | + * QEMU PowerPC 4xx emulation shared definitions | |
3 | + * | |
4 | + * Copyright (c) 2007 Jocelyn Mayer | |
5 | + * | |
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 | + */ | |
24 | + | |
25 | +#if !defined(PPC_4XX_H) | |
26 | +#define PPC_4XX_H | |
27 | + | |
28 | +/* PowerPC 4xx core initialization */ | |
29 | +CPUState *ppc4xx_init (const unsigned char *cpu_model, | |
30 | + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, | |
31 | + uint32_t sysclk); | |
32 | + | |
33 | +typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; | |
34 | +int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, | |
35 | + target_phys_addr_t offset, uint32_t len, | |
36 | + CPUReadMemoryFunc **mem_read, | |
37 | + CPUWriteMemoryFunc **mem_write, void *opaque); | |
38 | +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base); | |
39 | + | |
40 | +/* PowerPC 4xx universal interrupt controller */ | |
41 | +enum { | |
42 | + PPCUIC_OUTPUT_INT = 0, | |
43 | + PPCUIC_OUTPUT_CINT = 1, | |
44 | + PPCUIC_OUTPUT_NB, | |
45 | +}; | |
46 | +qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, | |
47 | + uint32_t dcr_base, int has_ssr, int has_vr); | |
48 | + | |
49 | +#endif /* !defined(PPC_4XX_H) */ | ... | ... |
hw/ppc4xx_devs.c
0 โ 100644
1 | +/* | |
2 | + * QEMU PowerPC 4xx embedded processors shared devices emulation | |
3 | + * | |
4 | + * Copyright (c) 2007 Jocelyn Mayer | |
5 | + * | |
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 | + */ | |
24 | +#include "vl.h" | |
25 | +#include "ppc4xx.h" | |
26 | + | |
27 | +extern int loglevel; | |
28 | +extern FILE *logfile; | |
29 | + | |
30 | +//#define DEBUG_MMIO | |
31 | +#define DEBUG_UIC | |
32 | + | |
33 | +/*****************************************************************************/ | |
34 | +/* Generic PowerPC 4xx processor instanciation */ | |
35 | +CPUState *ppc4xx_init (const unsigned char *cpu_model, | |
36 | + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, | |
37 | + uint32_t sysclk) | |
38 | +{ | |
39 | + CPUState *env; | |
40 | + ppc_def_t *def; | |
41 | + | |
42 | + /* init CPUs */ | |
43 | + env = cpu_init(); | |
44 | + ppc_find_by_name(cpu_model, &def); | |
45 | + if (def == NULL) { | |
46 | + cpu_abort(env, "Unable to find PowerPC %s CPU definition\n", | |
47 | + cpu_model); | |
48 | + } | |
49 | + cpu_ppc_register(env, def); | |
50 | + cpu_ppc_reset(env); | |
51 | + cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ | |
52 | + cpu_clk->opaque = env; | |
53 | + /* Set time-base frequency to sysclk */ | |
54 | + tb_clk->cb = ppc_emb_timers_init(env, sysclk); | |
55 | + tb_clk->opaque = env; | |
56 | + ppc_dcr_init(env, NULL, NULL); | |
57 | + /* Register qemu callbacks */ | |
58 | + qemu_register_reset(&cpu_ppc_reset, env); | |
59 | + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); | |
60 | + | |
61 | + return env; | |
62 | +} | |
63 | + | |
64 | +/*****************************************************************************/ | |
65 | +/* Fake device used to map multiple devices in a single memory page */ | |
66 | +#define MMIO_AREA_BITS 8 | |
67 | +#define MMIO_AREA_LEN (1 << MMIO_AREA_BITS) | |
68 | +#define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) | |
69 | +#define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) | |
70 | +struct ppc4xx_mmio_t { | |
71 | + target_phys_addr_t base; | |
72 | + CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; | |
73 | + CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; | |
74 | + void *opaque[MMIO_AREA_NB]; | |
75 | +}; | |
76 | + | |
77 | +static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr) | |
78 | +{ | |
79 | +#ifdef DEBUG_UNASSIGNED | |
80 | + ppc4xx_mmio_t *mmio; | |
81 | + | |
82 | + mmio = opaque; | |
83 | + printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n", | |
84 | + addr, mmio->base); | |
85 | +#endif | |
86 | + | |
87 | + return 0; | |
88 | +} | |
89 | + | |
90 | +static void unassigned_mmio_writeb (void *opaque, | |
91 | + target_phys_addr_t addr, uint32_t val) | |
92 | +{ | |
93 | +#ifdef DEBUG_UNASSIGNED | |
94 | + ppc4xx_mmio_t *mmio; | |
95 | + | |
96 | + mmio = opaque; | |
97 | + printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n", | |
98 | + addr, val, mmio->base); | |
99 | +#endif | |
100 | +} | |
101 | + | |
102 | +static CPUReadMemoryFunc *unassigned_mmio_read[3] = { | |
103 | + unassigned_mmio_readb, | |
104 | + unassigned_mmio_readb, | |
105 | + unassigned_mmio_readb, | |
106 | +}; | |
107 | + | |
108 | +static CPUWriteMemoryFunc *unassigned_mmio_write[3] = { | |
109 | + unassigned_mmio_writeb, | |
110 | + unassigned_mmio_writeb, | |
111 | + unassigned_mmio_writeb, | |
112 | +}; | |
113 | + | |
114 | +static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, | |
115 | + target_phys_addr_t addr, int len) | |
116 | +{ | |
117 | + CPUReadMemoryFunc **mem_read; | |
118 | + uint32_t ret; | |
119 | + int idx; | |
120 | + | |
121 | + idx = MMIO_IDX(addr - mmio->base); | |
122 | +#if defined(DEBUG_MMIO) | |
123 | + printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__, | |
124 | + mmio, len, addr, idx); | |
125 | +#endif | |
126 | + mem_read = mmio->mem_read[idx]; | |
127 | + ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base); | |
128 | + | |
129 | + return ret; | |
130 | +} | |
131 | + | |
132 | +static void mmio_writelen (ppc4xx_mmio_t *mmio, | |
133 | + target_phys_addr_t addr, uint32_t value, int len) | |
134 | +{ | |
135 | + CPUWriteMemoryFunc **mem_write; | |
136 | + int idx; | |
137 | + | |
138 | + idx = MMIO_IDX(addr - mmio->base); | |
139 | +#if defined(DEBUG_MMIO) | |
140 | + printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__, | |
141 | + mmio, len, addr, idx, value); | |
142 | +#endif | |
143 | + mem_write = mmio->mem_write[idx]; | |
144 | + (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value); | |
145 | +} | |
146 | + | |
147 | +static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) | |
148 | +{ | |
149 | +#if defined(DEBUG_MMIO) | |
150 | + printf("%s: addr " PADDRX "\n", __func__, addr); | |
151 | +#endif | |
152 | + | |
153 | + return mmio_readlen(opaque, addr, 0); | |
154 | +} | |
155 | + | |
156 | +static void mmio_writeb (void *opaque, | |
157 | + target_phys_addr_t addr, uint32_t value) | |
158 | +{ | |
159 | +#if defined(DEBUG_MMIO) | |
160 | + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); | |
161 | +#endif | |
162 | + mmio_writelen(opaque, addr, value, 0); | |
163 | +} | |
164 | + | |
165 | +static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr) | |
166 | +{ | |
167 | +#if defined(DEBUG_MMIO) | |
168 | + printf("%s: addr " PADDRX "\n", __func__, addr); | |
169 | +#endif | |
170 | + | |
171 | + return mmio_readlen(opaque, addr, 1); | |
172 | +} | |
173 | + | |
174 | +static void mmio_writew (void *opaque, | |
175 | + target_phys_addr_t addr, uint32_t value) | |
176 | +{ | |
177 | +#if defined(DEBUG_MMIO) | |
178 | + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); | |
179 | +#endif | |
180 | + mmio_writelen(opaque, addr, value, 1); | |
181 | +} | |
182 | + | |
183 | +static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr) | |
184 | +{ | |
185 | +#if defined(DEBUG_MMIO) | |
186 | + printf("%s: addr " PADDRX "\n", __func__, addr); | |
187 | +#endif | |
188 | + | |
189 | + return mmio_readlen(opaque, addr, 2); | |
190 | +} | |
191 | + | |
192 | +static void mmio_writel (void *opaque, | |
193 | + target_phys_addr_t addr, uint32_t value) | |
194 | +{ | |
195 | +#if defined(DEBUG_MMIO) | |
196 | + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); | |
197 | +#endif | |
198 | + mmio_writelen(opaque, addr, value, 2); | |
199 | +} | |
200 | + | |
201 | +static CPUReadMemoryFunc *mmio_read[] = { | |
202 | + &mmio_readb, | |
203 | + &mmio_readw, | |
204 | + &mmio_readl, | |
205 | +}; | |
206 | + | |
207 | +static CPUWriteMemoryFunc *mmio_write[] = { | |
208 | + &mmio_writeb, | |
209 | + &mmio_writew, | |
210 | + &mmio_writel, | |
211 | +}; | |
212 | + | |
213 | +int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, | |
214 | + target_phys_addr_t offset, uint32_t len, | |
215 | + CPUReadMemoryFunc **mem_read, | |
216 | + CPUWriteMemoryFunc **mem_write, void *opaque) | |
217 | +{ | |
218 | + uint32_t end; | |
219 | + int idx, eidx; | |
220 | + | |
221 | + if ((offset + len) > TARGET_PAGE_SIZE) | |
222 | + return -1; | |
223 | + idx = MMIO_IDX(offset); | |
224 | + end = offset + len - 1; | |
225 | + eidx = MMIO_IDX(end); | |
226 | +#if defined(DEBUG_MMIO) | |
227 | + printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len, | |
228 | + end, idx, eidx); | |
229 | +#endif | |
230 | + for (; idx <= eidx; idx++) { | |
231 | + mmio->mem_read[idx] = mem_read; | |
232 | + mmio->mem_write[idx] = mem_write; | |
233 | + mmio->opaque[idx] = opaque; | |
234 | + } | |
235 | + | |
236 | + return 0; | |
237 | +} | |
238 | + | |
239 | +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) | |
240 | +{ | |
241 | + ppc4xx_mmio_t *mmio; | |
242 | + int mmio_memory; | |
243 | + | |
244 | + mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); | |
245 | + if (mmio != NULL) { | |
246 | + mmio->base = base; | |
247 | + mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); | |
248 | +#if defined(DEBUG_MMIO) | |
249 | + printf("%s: %p base %08x len %08x %d\n", __func__, | |
250 | + mmio, base, TARGET_PAGE_SIZE, mmio_memory); | |
251 | +#endif | |
252 | + cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); | |
253 | + ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, | |
254 | + unassigned_mmio_read, unassigned_mmio_write, | |
255 | + mmio); | |
256 | + } | |
257 | + | |
258 | + return mmio; | |
259 | +} | |
260 | + | |
261 | +/*****************************************************************************/ | |
262 | +/* "Universal" Interrupt controller */ | |
263 | +enum { | |
264 | + DCR_UICSR = 0x000, | |
265 | + DCR_UICSRS = 0x001, | |
266 | + DCR_UICER = 0x002, | |
267 | + DCR_UICCR = 0x003, | |
268 | + DCR_UICPR = 0x004, | |
269 | + DCR_UICTR = 0x005, | |
270 | + DCR_UICMSR = 0x006, | |
271 | + DCR_UICVR = 0x007, | |
272 | + DCR_UICVCR = 0x008, | |
273 | + DCR_UICMAX = 0x009, | |
274 | +}; | |
275 | + | |
276 | +#define UIC_MAX_IRQ 32 | |
277 | +typedef struct ppcuic_t ppcuic_t; | |
278 | +struct ppcuic_t { | |
279 | + uint32_t dcr_base; | |
280 | + int use_vectors; | |
281 | + uint32_t uicsr; /* Status register */ | |
282 | + uint32_t uicer; /* Enable register */ | |
283 | + uint32_t uiccr; /* Critical register */ | |
284 | + uint32_t uicpr; /* Polarity register */ | |
285 | + uint32_t uictr; /* Triggering register */ | |
286 | + uint32_t uicvcr; /* Vector configuration register */ | |
287 | + uint32_t uicvr; | |
288 | + qemu_irq *irqs; | |
289 | +}; | |
290 | + | |
291 | +static void ppcuic_trigger_irq (ppcuic_t *uic) | |
292 | +{ | |
293 | + uint32_t ir, cr; | |
294 | + int start, end, inc, i; | |
295 | + | |
296 | + /* Trigger interrupt if any is pending */ | |
297 | + ir = uic->uicsr & uic->uicer & (~uic->uiccr); | |
298 | + cr = uic->uicsr & uic->uicer & uic->uiccr; | |
299 | +#ifdef DEBUG_UIC | |
300 | + if (loglevel & CPU_LOG_INT) { | |
301 | + fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n" | |
302 | + " %08x ir %08x cr %08x\n", __func__, | |
303 | + uic->uicsr, uic->uicer, uic->uiccr, | |
304 | + uic->uicsr & uic->uicer, ir, cr); | |
305 | + } | |
306 | +#endif | |
307 | + if (ir != 0x0000000) { | |
308 | +#ifdef DEBUG_UIC | |
309 | + if (loglevel & CPU_LOG_INT) { | |
310 | + fprintf(logfile, "Raise UIC interrupt\n"); | |
311 | + } | |
312 | +#endif | |
313 | + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); | |
314 | + } else { | |
315 | +#ifdef DEBUG_UIC | |
316 | + if (loglevel & CPU_LOG_INT) { | |
317 | + fprintf(logfile, "Lower UIC interrupt\n"); | |
318 | + } | |
319 | +#endif | |
320 | + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); | |
321 | + } | |
322 | + /* Trigger critical interrupt if any is pending and update vector */ | |
323 | + if (cr != 0x0000000) { | |
324 | + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); | |
325 | + if (uic->use_vectors) { | |
326 | + /* Compute critical IRQ vector */ | |
327 | + if (uic->uicvcr & 1) { | |
328 | + start = 31; | |
329 | + end = 0; | |
330 | + inc = -1; | |
331 | + } else { | |
332 | + start = 0; | |
333 | + end = 31; | |
334 | + inc = 1; | |
335 | + } | |
336 | + uic->uicvr = uic->uicvcr & 0xFFFFFFFC; | |
337 | + for (i = start; i <= end; i += inc) { | |
338 | + if (cr & (1 << i)) { | |
339 | + uic->uicvr += (i - start) * 512 * inc; | |
340 | + break; | |
341 | + } | |
342 | + } | |
343 | + } | |
344 | +#ifdef DEBUG_UIC | |
345 | + if (loglevel & CPU_LOG_INT) { | |
346 | + fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n", | |
347 | + uic->uicvr); | |
348 | + } | |
349 | +#endif | |
350 | + } else { | |
351 | +#ifdef DEBUG_UIC | |
352 | + if (loglevel & CPU_LOG_INT) { | |
353 | + fprintf(logfile, "Lower UIC critical interrupt\n"); | |
354 | + } | |
355 | +#endif | |
356 | + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); | |
357 | + uic->uicvr = 0x00000000; | |
358 | + } | |
359 | +} | |
360 | + | |
361 | +static void ppcuic_set_irq (void *opaque, int irq_num, int level) | |
362 | +{ | |
363 | + ppcuic_t *uic; | |
364 | + uint32_t mask, sr; | |
365 | + | |
366 | + uic = opaque; | |
367 | + mask = 1 << irq_num; | |
368 | +#ifdef DEBUG_UIC | |
369 | + if (loglevel & CPU_LOG_INT) { | |
370 | + fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x " | |
371 | + "%08x\n", __func__, irq_num, level, | |
372 | + uic->uicsr, mask, uic->uicsr & mask, level << irq_num); | |
373 | + } | |
374 | +#endif | |
375 | + if (irq_num < 0 || irq_num > 31) | |
376 | + return; | |
377 | + sr = uic->uicsr; | |
378 | + if (!(uic->uicpr & mask)) { | |
379 | + /* Negatively asserted IRQ */ | |
380 | + level = level == 0 ? 1 : 0; | |
381 | + } | |
382 | + /* Update status register */ | |
383 | + if (uic->uictr & mask) { | |
384 | + /* Edge sensitive interrupt */ | |
385 | + if (level == 1) | |
386 | + uic->uicsr |= mask; | |
387 | + } else { | |
388 | + /* Level sensitive interrupt */ | |
389 | + if (level == 1) | |
390 | + uic->uicsr |= mask; | |
391 | + else | |
392 | + uic->uicsr &= ~mask; | |
393 | + } | |
394 | +#ifdef DEBUG_UIC | |
395 | + if (loglevel & CPU_LOG_INT) { | |
396 | + fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__, | |
397 | + irq_num, level, uic->uicsr, sr); | |
398 | + } | |
399 | +#endif | |
400 | + if (sr != uic->uicsr) | |
401 | + ppcuic_trigger_irq(uic); | |
402 | +} | |
403 | + | |
404 | +static target_ulong dcr_read_uic (void *opaque, int dcrn) | |
405 | +{ | |
406 | + ppcuic_t *uic; | |
407 | + target_ulong ret; | |
408 | + | |
409 | + uic = opaque; | |
410 | + dcrn -= uic->dcr_base; | |
411 | + switch (dcrn) { | |
412 | + case DCR_UICSR: | |
413 | + case DCR_UICSRS: | |
414 | + ret = uic->uicsr; | |
415 | + break; | |
416 | + case DCR_UICER: | |
417 | + ret = uic->uicer; | |
418 | + break; | |
419 | + case DCR_UICCR: | |
420 | + ret = uic->uiccr; | |
421 | + break; | |
422 | + case DCR_UICPR: | |
423 | + ret = uic->uicpr; | |
424 | + break; | |
425 | + case DCR_UICTR: | |
426 | + ret = uic->uictr; | |
427 | + break; | |
428 | + case DCR_UICMSR: | |
429 | + ret = uic->uicsr & uic->uicer; | |
430 | + break; | |
431 | + case DCR_UICVR: | |
432 | + if (!uic->use_vectors) | |
433 | + goto no_read; | |
434 | + ret = uic->uicvr; | |
435 | + break; | |
436 | + case DCR_UICVCR: | |
437 | + if (!uic->use_vectors) | |
438 | + goto no_read; | |
439 | + ret = uic->uicvcr; | |
440 | + break; | |
441 | + default: | |
442 | + no_read: | |
443 | + ret = 0x00000000; | |
444 | + break; | |
445 | + } | |
446 | + | |
447 | + return ret; | |
448 | +} | |
449 | + | |
450 | +static void dcr_write_uic (void *opaque, int dcrn, target_ulong val) | |
451 | +{ | |
452 | + ppcuic_t *uic; | |
453 | + | |
454 | + uic = opaque; | |
455 | + dcrn -= uic->dcr_base; | |
456 | +#ifdef DEBUG_UIC | |
457 | + if (loglevel & CPU_LOG_INT) { | |
458 | + fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val); | |
459 | + } | |
460 | +#endif | |
461 | + switch (dcrn) { | |
462 | + case DCR_UICSR: | |
463 | + uic->uicsr &= ~val; | |
464 | + ppcuic_trigger_irq(uic); | |
465 | + break; | |
466 | + case DCR_UICSRS: | |
467 | + uic->uicsr |= val; | |
468 | + ppcuic_trigger_irq(uic); | |
469 | + break; | |
470 | + case DCR_UICER: | |
471 | + uic->uicer = val; | |
472 | + ppcuic_trigger_irq(uic); | |
473 | + break; | |
474 | + case DCR_UICCR: | |
475 | + uic->uiccr = val; | |
476 | + ppcuic_trigger_irq(uic); | |
477 | + break; | |
478 | + case DCR_UICPR: | |
479 | + uic->uicpr = val; | |
480 | + ppcuic_trigger_irq(uic); | |
481 | + break; | |
482 | + case DCR_UICTR: | |
483 | + uic->uictr = val; | |
484 | + ppcuic_trigger_irq(uic); | |
485 | + break; | |
486 | + case DCR_UICMSR: | |
487 | + break; | |
488 | + case DCR_UICVR: | |
489 | + break; | |
490 | + case DCR_UICVCR: | |
491 | + uic->uicvcr = val & 0xFFFFFFFD; | |
492 | + ppcuic_trigger_irq(uic); | |
493 | + break; | |
494 | + } | |
495 | +} | |
496 | + | |
497 | +static void ppcuic_reset (void *opaque) | |
498 | +{ | |
499 | + ppcuic_t *uic; | |
500 | + | |
501 | + uic = opaque; | |
502 | + uic->uiccr = 0x00000000; | |
503 | + uic->uicer = 0x00000000; | |
504 | + uic->uicpr = 0x00000000; | |
505 | + uic->uicsr = 0x00000000; | |
506 | + uic->uictr = 0x00000000; | |
507 | + if (uic->use_vectors) { | |
508 | + uic->uicvcr = 0x00000000; | |
509 | + uic->uicvr = 0x0000000; | |
510 | + } | |
511 | +} | |
512 | + | |
513 | +qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, | |
514 | + uint32_t dcr_base, int has_ssr, int has_vr) | |
515 | +{ | |
516 | + ppcuic_t *uic; | |
517 | + int i; | |
518 | + | |
519 | + uic = qemu_mallocz(sizeof(ppcuic_t)); | |
520 | + if (uic != NULL) { | |
521 | + uic->dcr_base = dcr_base; | |
522 | + uic->irqs = irqs; | |
523 | + if (has_vr) | |
524 | + uic->use_vectors = 1; | |
525 | + for (i = 0; i < DCR_UICMAX; i++) { | |
526 | + ppc_dcr_register(env, dcr_base + i, uic, | |
527 | + &dcr_read_uic, &dcr_write_uic); | |
528 | + } | |
529 | + qemu_register_reset(ppcuic_reset, uic); | |
530 | + ppcuic_reset(uic); | |
531 | + } | |
532 | + | |
533 | + return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); | |
534 | +} | ... | ... |