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,6 +25,8 @@ | ||
25 | #if !defined(PPC_405_H) | 25 | #if !defined(PPC_405_H) |
26 | #define PPC_405_H | 26 | #define PPC_405_H |
27 | 27 | ||
28 | +#include "ppc4xx.h" | ||
29 | + | ||
28 | /* Bootinfo as set-up by u-boot */ | 30 | /* Bootinfo as set-up by u-boot */ |
29 | typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; | 31 | typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; |
30 | struct ppc4xx_bd_info_t { | 32 | struct ppc4xx_bd_info_t { |
@@ -54,19 +56,9 @@ struct ppc4xx_bd_info_t { | @@ -54,19 +56,9 @@ struct ppc4xx_bd_info_t { | ||
54 | }; | 56 | }; |
55 | 57 | ||
56 | /* PowerPC 405 core */ | 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 | ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, | 59 | ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, |
61 | uint32_t flags); | 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 | /* PowerPC 4xx peripheral local bus arbitrer */ | 62 | /* PowerPC 4xx peripheral local bus arbitrer */ |
71 | void ppc4xx_plb_init (CPUState *env); | 63 | void ppc4xx_plb_init (CPUState *env); |
72 | /* PLB to OPB bridge */ | 64 | /* PLB to OPB bridge */ |
@@ -74,14 +66,6 @@ void ppc4xx_pob_init (CPUState *env); | @@ -74,14 +66,6 @@ void ppc4xx_pob_init (CPUState *env); | ||
74 | /* OPB arbitrer */ | 66 | /* OPB arbitrer */ |
75 | void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, | 67 | void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, |
76 | target_phys_addr_t offset); | 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 | /* SDRAM controller */ | 69 | /* SDRAM controller */ |
86 | void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, | 70 | void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, |
87 | target_phys_addr_t *ram_bases, | 71 | target_phys_addr_t *ram_bases, |
hw/ppc405_uc.c
@@ -27,7 +27,6 @@ | @@ -27,7 +27,6 @@ | ||
27 | extern int loglevel; | 27 | extern int loglevel; |
28 | extern FILE *logfile; | 28 | extern FILE *logfile; |
29 | 29 | ||
30 | -//#define DEBUG_MMIO | ||
31 | #define DEBUG_OPBA | 30 | #define DEBUG_OPBA |
32 | #define DEBUG_SDRAM | 31 | #define DEBUG_SDRAM |
33 | #define DEBUG_GPIO | 32 | #define DEBUG_GPIO |
@@ -36,41 +35,9 @@ extern FILE *logfile; | @@ -36,41 +35,9 @@ extern FILE *logfile; | ||
36 | //#define DEBUG_I2C | 35 | //#define DEBUG_I2C |
37 | #define DEBUG_GPT | 36 | #define DEBUG_GPT |
38 | #define DEBUG_MAL | 37 | #define DEBUG_MAL |
39 | -#define DEBUG_UIC | ||
40 | #define DEBUG_CLOCKS | 38 | #define DEBUG_CLOCKS |
41 | //#define DEBUG_UNASSIGNED | 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 | ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, | 41 | ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, |
75 | uint32_t flags) | 42 | uint32_t flags) |
76 | { | 43 | { |
@@ -124,203 +91,6 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, | @@ -124,203 +91,6 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, | ||
124 | /* Shared peripherals */ | 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 | /* Peripheral local bus arbitrer */ | 94 | /* Peripheral local bus arbitrer */ |
325 | enum { | 95 | enum { |
326 | PLB0_BESR = 0x084, | 96 | PLB0_BESR = 0x084, |
@@ -625,281 +395,6 @@ void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, | @@ -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 | /* Code decompression controller */ | 398 | /* Code decompression controller */ |
904 | /* XXX: TODO */ | 399 | /* XXX: TODO */ |
905 | 400 | ||
@@ -3040,7 +2535,7 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4], | @@ -3040,7 +2535,7 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4], | ||
3040 | int i; | 2535 | int i; |
3041 | 2536 | ||
3042 | memset(clk_setup, 0, sizeof(clk_setup)); | 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 | &clk_setup[PPC405CR_TMR_CLK], sysclk); | 2539 | &clk_setup[PPC405CR_TMR_CLK], sysclk); |
3045 | /* Memory mapped devices registers */ | 2540 | /* Memory mapped devices registers */ |
3046 | mmio = ppc4xx_mmio_init(env, 0xEF600000); | 2541 | mmio = ppc4xx_mmio_init(env, 0xEF600000); |
@@ -3390,7 +2885,7 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2], | @@ -3390,7 +2885,7 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2], | ||
3390 | 2885 | ||
3391 | memset(clk_setup, 0, sizeof(clk_setup)); | 2886 | memset(clk_setup, 0, sizeof(clk_setup)); |
3392 | /* init CPUs */ | 2887 | /* init CPUs */ |
3393 | - env = ppc405_init("405ep", &clk_setup[PPC405EP_CPU_CLK], | 2888 | + env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], |
3394 | &tlb_clk_setup, sysclk); | 2889 | &tlb_clk_setup, sysclk); |
3395 | clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; | 2890 | clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; |
3396 | clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; | 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 | +} |