Statistics
| Branch: | Revision:

root / hw / sh7750.c @ 2f062c72

History | View | Annotate | Download (10.4 kB)

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
}