Add INTC controller prototype, by Magnus Damm.
[qemu] / hw / sh7750.c
1 /*
2  * SH7750 device
3  *
4  * Copyright (c) 2005 Samuel Tardieu
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 <stdio.h>
25 #include <assert.h>
26 #include "vl.h"
27 #include "sh7750_regs.h"
28 #include "sh7750_regnames.h"
29
30 #define NB_DEVICES 4
31
32 typedef struct SH7750State {
33     /* CPU */
34     CPUSH4State *cpu;
35     /* Peripheral frequency in Hz */
36     uint32_t periph_freq;
37     /* SDRAM controller */
38     uint16_t rfcr;
39     /* IO ports */
40     uint16_t gpioic;
41     uint32_t pctra;
42     uint32_t pctrb;
43     uint16_t portdira;          /* Cached */
44     uint16_t portpullupa;       /* Cached */
45     uint16_t portdirb;          /* Cached */
46     uint16_t portpullupb;       /* Cached */
47     uint16_t pdtra;
48     uint16_t pdtrb;
49     uint16_t periph_pdtra;      /* Imposed by the peripherals */
50     uint16_t periph_portdira;   /* Direction seen from the peripherals */
51     uint16_t periph_pdtrb;      /* Imposed by the peripherals */
52     uint16_t periph_portdirb;   /* Direction seen from the peripherals */
53     sh7750_io_device *devices[NB_DEVICES];      /* External peripherals */
54
55     uint16_t icr;
56     uint16_t ipra;
57     uint16_t iprb;
58     uint16_t iprc;
59     uint16_t iprd;
60     uint32_t intpri00;
61     uint32_t intmsk00;
62     /* Cache */
63     uint32_t ccr;
64
65 } SH7750State;
66
67
68 /**********************************************************************
69  I/O ports
70 **********************************************************************/
71
72 int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device)
73 {
74     int i;
75
76     for (i = 0; i < NB_DEVICES; i++) {
77         if (s->devices[i] == NULL) {
78             s->devices[i] = device;
79             return 0;
80         }
81     }
82     return -1;
83 }
84
85 static uint16_t portdir(uint32_t v)
86 {
87 #define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n))
88     return
89         EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) |
90         EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) |
91         EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) |
92         EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) |
93         EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) |
94         EVENPORTMASK(0);
95 }
96
97 static uint16_t portpullup(uint32_t v)
98 {
99 #define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n))
100     return
101         ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) |
102         ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) |
103         ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) |
104         ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) |
105         ODDPORTMASK(1) | ODDPORTMASK(0);
106 }
107
108 static uint16_t porta_lines(SH7750State * s)
109 {
110     return (s->portdira & s->pdtra) |   /* CPU */
111         (s->periph_portdira & s->periph_pdtra) |        /* Peripherals */
112         (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */
113 }
114
115 static uint16_t portb_lines(SH7750State * s)
116 {
117     return (s->portdirb & s->pdtrb) |   /* CPU */
118         (s->periph_portdirb & s->periph_pdtrb) |        /* Peripherals */
119         (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */
120 }
121
122 static void gen_port_interrupts(SH7750State * s)
123 {
124     /* XXXXX interrupts not generated */
125 }
126
127 static void porta_changed(SH7750State * s, uint16_t prev)
128 {
129     uint16_t currenta, changes;
130     int i, r = 0;
131
132 #if 0
133     fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n",
134             prev, porta_lines(s));
135     fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra);
136 #endif
137     currenta = porta_lines(s);
138     if (currenta == prev)
139         return;
140     changes = currenta ^ prev;
141
142     for (i = 0; i < NB_DEVICES; i++) {
143         if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) {
144             r |= s->devices[i]->port_change_cb(currenta, portb_lines(s),
145                                                &s->periph_pdtra,
146                                                &s->periph_portdira,
147                                                &s->periph_pdtrb,
148                                                &s->periph_portdirb);
149         }
150     }
151
152     if (r)
153         gen_port_interrupts(s);
154 }
155
156 static void portb_changed(SH7750State * s, uint16_t prev)
157 {
158     uint16_t currentb, changes;
159     int i, r = 0;
160
161     currentb = portb_lines(s);
162     if (currentb == prev)
163         return;
164     changes = currentb ^ prev;
165
166     for (i = 0; i < NB_DEVICES; i++) {
167         if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) {
168             r |= s->devices[i]->port_change_cb(portb_lines(s), currentb,
169                                                &s->periph_pdtra,
170                                                &s->periph_portdira,
171                                                &s->periph_pdtrb,
172                                                &s->periph_portdirb);
173         }
174     }
175
176     if (r)
177         gen_port_interrupts(s);
178 }
179
180 /**********************************************************************
181  Memory
182 **********************************************************************/
183
184 static void error_access(const char *kind, target_phys_addr_t addr)
185 {
186     fprintf(stderr, "%s to %s (0x%08x) not supported\n",
187             kind, regname(addr), addr);
188 }
189
190 static void ignore_access(const char *kind, target_phys_addr_t addr)
191 {
192     fprintf(stderr, "%s to %s (0x%08x) ignored\n",
193             kind, regname(addr), addr);
194 }
195
196 static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr)
197 {
198     switch (addr) {
199     default:
200         error_access("byte read", addr);
201         assert(0);
202     }
203 }
204
205 static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr)
206 {
207     SH7750State *s = opaque;
208
209     switch (addr) {
210     case SH7750_RFCR_A7:
211         fprintf(stderr,
212                 "Read access to refresh count register, incrementing\n");
213         return s->rfcr++;
214     case SH7750_PDTRA_A7:
215         return porta_lines(s);
216     case SH7750_PDTRB_A7:
217         return portb_lines(s);
218     case 0x1fd00000:
219         return s->icr;
220     case 0x1fd00004:
221         return s->ipra;
222     case 0x1fd00008:
223         return s->iprb;
224     case 0x1fd0000c:
225         return s->iprc;
226     case 0x1fd00010:
227         return s->iprd;
228     default:
229         error_access("word read", addr);
230         assert(0);
231     }
232 }
233
234 static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr)
235 {
236     SH7750State *s = opaque;
237
238     switch (addr) {
239     case SH7750_MMUCR_A7:
240         return s->cpu->mmucr;
241     case SH7750_PTEH_A7:
242         return s->cpu->pteh;
243     case SH7750_PTEL_A7:
244         return s->cpu->ptel;
245     case SH7750_TTB_A7:
246         return s->cpu->ttb;
247     case SH7750_TEA_A7:
248         return s->cpu->tea;
249     case SH7750_TRA_A7:
250         return s->cpu->tra;
251     case SH7750_EXPEVT_A7:
252         return s->cpu->expevt;
253     case SH7750_INTEVT_A7:
254         return s->cpu->intevt;
255     case SH7750_CCR_A7:
256         return s->ccr;
257     case 0x1f000030:            /* Processor version PVR */
258         return 0x00050000;      /* SH7750R */
259     case 0x1f000040:            /* Processor version CVR */
260         return 0x00110000;      /* Minimum caches */
261     case 0x1f000044:            /* Processor version PRR */
262         return 0x00000100;      /* SH7750R */
263     case 0x1e080000:
264         return s->intpri00;
265     case 0x1e080020:
266         return 0;
267     case 0x1e080040:
268         return s->intmsk00;
269     case 0x1e080060:
270         return 0;
271     default:
272         error_access("long read", addr);
273         assert(0);
274     }
275 }
276
277 static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr,
278                               uint32_t mem_value)
279 {
280     switch (addr) {
281         /* PRECHARGE ? XXXXX */
282     case SH7750_PRECHARGE0_A7:
283     case SH7750_PRECHARGE1_A7:
284         ignore_access("byte write", addr);
285         return;
286     default:
287         error_access("byte write", addr);
288         assert(0);
289     }
290 }
291
292 static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr,
293                               uint32_t mem_value)
294 {
295     SH7750State *s = opaque;
296     uint16_t temp;
297
298     switch (addr) {
299         /* SDRAM controller */
300     case SH7750_BCR2_A7:
301     case SH7750_BCR3_A7:
302     case SH7750_RTCOR_A7:
303     case SH7750_RTCNT_A7:
304     case SH7750_RTCSR_A7:
305         ignore_access("word write", addr);
306         return;
307         /* IO ports */
308     case SH7750_PDTRA_A7:
309         temp = porta_lines(s);
310         s->pdtra = mem_value;
311         porta_changed(s, temp);
312         return;
313     case SH7750_PDTRB_A7:
314         temp = portb_lines(s);
315         s->pdtrb = mem_value;
316         portb_changed(s, temp);
317         return;
318     case SH7750_RFCR_A7:
319         fprintf(stderr, "Write access to refresh count register\n");
320         s->rfcr = mem_value;
321         return;
322     case SH7750_GPIOIC_A7:
323         s->gpioic = mem_value;
324         if (mem_value != 0) {
325             fprintf(stderr, "I/O interrupts not implemented\n");
326             assert(0);
327         }
328         return;
329     case 0x1fd00000:
330         s->icr = mem_value;
331         return;
332     case 0x1fd00004:
333         s->ipra = mem_value;
334         return;
335     case 0x1fd00008:
336         s->iprb = mem_value;
337         return;
338     case 0x1fd0000c:
339         s->iprc = mem_value;
340         return;
341     case 0x1fd00010:
342         s->iprd = mem_value;
343         return;
344     default:
345         error_access("word write", addr);
346         assert(0);
347     }
348 }
349
350 static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr,
351                               uint32_t mem_value)
352 {
353     SH7750State *s = opaque;
354     uint16_t temp;
355
356     switch (addr) {
357         /* SDRAM controller */
358     case SH7750_BCR1_A7:
359     case SH7750_BCR4_A7:
360     case SH7750_WCR1_A7:
361     case SH7750_WCR2_A7:
362     case SH7750_WCR3_A7:
363     case SH7750_MCR_A7:
364         ignore_access("long write", addr);
365         return;
366         /* IO ports */
367     case SH7750_PCTRA_A7:
368         temp = porta_lines(s);
369         s->pctra = mem_value;
370         s->portdira = portdir(mem_value);
371         s->portpullupa = portpullup(mem_value);
372         porta_changed(s, temp);
373         return;
374     case SH7750_PCTRB_A7:
375         temp = portb_lines(s);
376         s->pctrb = mem_value;
377         s->portdirb = portdir(mem_value);
378         s->portpullupb = portpullup(mem_value);
379         portb_changed(s, temp);
380         return;
381     case SH7750_MMUCR_A7:
382         s->cpu->mmucr = mem_value;
383         return;
384     case SH7750_PTEH_A7:
385         s->cpu->pteh = mem_value;
386         return;
387     case SH7750_PTEL_A7:
388         s->cpu->ptel = mem_value;
389         return;
390     case SH7750_TTB_A7:
391         s->cpu->ttb = mem_value;
392         return;
393     case SH7750_TEA_A7:
394         s->cpu->tea = mem_value;
395         return;
396     case SH7750_TRA_A7:
397         s->cpu->tra = mem_value & 0x000007ff;
398         return;
399     case SH7750_EXPEVT_A7:
400         s->cpu->expevt = mem_value & 0x000007ff;
401         return;
402     case SH7750_INTEVT_A7:
403         s->cpu->intevt = mem_value & 0x000007ff;
404         return;
405     case SH7750_CCR_A7:
406         s->ccr = mem_value;
407         return;
408     case 0x1e080000:
409         s->intpri00 = mem_value;
410         return;
411     case 0x1e080020:
412         return;
413     case 0x1e080040:
414         s->intmsk00 = mem_value;
415         return;
416     case 0x1e080060:
417         return;
418     default:
419         error_access("long write", addr);
420         assert(0);
421     }
422 }
423
424 static CPUReadMemoryFunc *sh7750_mem_read[] = {
425     sh7750_mem_readb,
426     sh7750_mem_readw,
427     sh7750_mem_readl
428 };
429
430 static CPUWriteMemoryFunc *sh7750_mem_write[] = {
431     sh7750_mem_writeb,
432     sh7750_mem_writew,
433     sh7750_mem_writel
434 };
435
436 SH7750State *sh7750_init(CPUSH4State * cpu)
437 {
438     SH7750State *s;
439     int sh7750_io_memory;
440
441     s = qemu_mallocz(sizeof(SH7750State));
442     s->cpu = cpu;
443     s->periph_freq = 60000000;  /* 60MHz */
444     sh7750_io_memory = cpu_register_io_memory(0,
445                                               sh7750_mem_read,
446                                               sh7750_mem_write, s);
447     cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory);
448
449     sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]);
450     sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF,
451                    s->periph_freq, serial_hds[1]);
452
453     tmu012_init(0x1fd80000,
454                 TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK,
455                 s->periph_freq);
456     tmu012_init(0x1e100000, 0, s->periph_freq);
457     return s;
458 }