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