Statistics
| Branch: | Revision:

root / hw / mips_r4k.c @ 6af0bf9c

History | View | Annotate | Download (8.1 kB)

1
#include "vl.h"
2

    
3
#define DEBUG_IRQ_COUNT
4

    
5
#define BIOS_FILENAME "mips_bios.bin"
6
//#define BIOS_FILENAME "system.bin"
7
#define KERNEL_LOAD_ADDR 0x80010000
8
#define INITRD_LOAD_ADDR 0x80800000
9

    
10
/* MIPS R4K IRQ controler */
11
#if defined(DEBUG_IRQ_COUNT)
12
static uint64_t irq_count[16];
13
#endif
14

    
15
extern FILE *logfile;
16

    
17
void mips_set_irq (int n_IRQ, int level)
18
{
19
    uint32_t mask;
20

    
21
    if (n_IRQ < 0 || n_IRQ >= 8)
22
        return;
23
    mask = 0x100 << n_IRQ;
24
    if (level != 0) {
25
#if 1
26
        if (logfile) {
27
            fprintf(logfile, "%s n %d l %d mask %08x %08x\n",
28
                    __func__, n_IRQ, level, mask, cpu_single_env->CP0_Status);
29
        }
30
#endif
31
        cpu_single_env->CP0_Cause |= mask;
32
        if ((cpu_single_env->CP0_Status & 0x00000001) &&
33
            (cpu_single_env->CP0_Status & mask)) {
34
#if defined(DEBUG_IRQ_COUNT)
35
            irq_count[n_IRQ]++;
36
#endif
37
#if 1
38
            if (logfile)
39
                fprintf(logfile, "%s raise IRQ\n", __func__);
40
#endif
41
            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
42
        }
43
    } else {
44
        cpu_single_env->CP0_Cause &= ~mask;
45
    }
46
}
47

    
48
void pic_set_irq (int n_IRQ, int level)
49
{
50
    mips_set_irq(n_IRQ + 2, level);
51
}
52

    
53
void pic_info (void)
54
{
55
    term_printf("IRQ asserted: %02x mask: %02x\n",
56
                (cpu_single_env->CP0_Cause >> 8) & 0xFF,
57
                (cpu_single_env->CP0_Status >> 8) & 0xFF);
58
}
59

    
60
void irq_info (void)
61
{
62
#if !defined(DEBUG_IRQ_COUNT)
63
    term_printf("irq statistic code not compiled.\n");
64
#else
65
    int i;
66
    int64_t count;
67

    
68
    term_printf("IRQ statistics:\n");
69
    for (i = 0; i < 8; i++) {
70
        count = irq_count[i];
71
        if (count > 0)
72
            term_printf("%2d: %lld\n", i, count);
73
    }
74
#endif
75
}
76

    
77
void cpu_mips_irqctrl_init (void)
78
{
79
}
80

    
81
/* MIPS R4K timer */
82
uint32_t cpu_mips_get_random (CPUState *env)
83
{
84
    uint64_t now = qemu_get_clock(vm_clock);
85

    
86
    return (uint32_t)now & 0x0000000F;
87
}
88

    
89
uint32_t cpu_mips_get_count (CPUState *env)
90
{
91
    return env->CP0_Count +
92
        (uint32_t)muldiv64(qemu_get_clock(vm_clock),
93
                           100 * 1000 * 1000, ticks_per_sec);
94
}
95

    
96
static void cpu_mips_update_count (CPUState *env, uint32_t count,
97
                                   uint32_t compare)
98
{
99
    uint64_t now, next;
100
    uint32_t tmp;
101
    
102
    tmp = count;
103
    if (count == compare)
104
        tmp++;
105
    now = qemu_get_clock(vm_clock);
106
    next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
107
    if (next == now)
108
        next++;
109
#if 1
110
    if (logfile) {
111
        fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
112
                __func__, now, count, compare, next - now);
113
    }
114
#endif
115
    /* Store new count and compare registers */
116
    env->CP0_Compare = compare;
117
    env->CP0_Count =
118
        count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
119
    /* Adjust timer */
120
    qemu_mod_timer(env->timer, next);
121
}
122

    
123
void cpu_mips_store_count (CPUState *env, uint32_t value)
124
{
125
    cpu_mips_update_count(env, value, env->CP0_Compare);
126
}
127

    
128
void cpu_mips_store_compare (CPUState *env, uint32_t value)
129
{
130
    cpu_mips_update_count(env, cpu_mips_get_count(env), value);
131
    pic_set_irq(5, 0);
132
}
133

    
134
static void mips_timer_cb (void *opaque)
135
{
136
    CPUState *env;
137

    
138
    env = opaque;
139
#if 1
140
    if (logfile) {
141
        fprintf(logfile, "%s\n", __func__);
142
    }
143
#endif
144
    cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
145
    pic_set_irq(5, 1);
146
}
147

    
148
void cpu_mips_clock_init (CPUState *env)
149
{
150
    env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
151
    env->CP0_Compare = 0;
152
    cpu_mips_update_count(env, 1, 0);
153
}
154

    
155
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
156
{
157
    if (logfile)
158
        fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
159
    cpu_outb(NULL, addr & 0xffff, value);
160
}
161

    
162
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
163
{
164
    uint32_t ret = cpu_inb(NULL, addr & 0xffff);
165
    if (logfile)
166
        fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
167
    return ret;
168
}
169

    
170
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
171
{
172
    if (logfile)
173
        fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
174
#ifdef TARGET_WORDS_BIGENDIAN
175
    value = bswap16(value);
176
#endif
177
    cpu_outw(NULL, addr & 0xffff, value);
178
}
179

    
180
static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
181
{
182
    uint32_t ret = cpu_inw(NULL, addr & 0xffff);
183
#ifdef TARGET_WORDS_BIGENDIAN
184
    ret = bswap16(ret);
185
#endif
186
    if (logfile)
187
        fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
188
    return ret;
189
}
190

    
191
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
192
{
193
    if (logfile)
194
        fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
195
#ifdef TARGET_WORDS_BIGENDIAN
196
    value = bswap32(value);
197
#endif
198
    cpu_outl(NULL, addr & 0xffff, value);
199
}
200

    
201
static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
202
{
203
    uint32_t ret = cpu_inl(NULL, addr & 0xffff);
204

    
205
#ifdef TARGET_WORDS_BIGENDIAN
206
    ret = bswap32(ret);
207
#endif
208
    if (logfile)
209
        fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
210
    return ret;
211
}
212

    
213
CPUWriteMemoryFunc *io_write[] = {
214
    &io_writeb,
215
    &io_writew,
216
    &io_writel,
217
};
218

    
219
CPUReadMemoryFunc *io_read[] = {
220
    &io_readb,
221
    &io_readw,
222
    &io_readl,
223
};
224

    
225
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
226
                    DisplayState *ds, const char **fd_filename, int snapshot,
227
                    const char *kernel_filename, const char *kernel_cmdline,
228
                    const char *initrd_filename)
229
{
230
    char buf[1024];
231
    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
232
    unsigned long bios_offset;
233
    int io_memory;
234
    int linux_boot;
235
    int ret;
236

    
237
    printf("%s: start\n", __func__);
238
    linux_boot = (kernel_filename != NULL);
239
    /* allocate RAM */
240
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
241
    bios_offset = ram_size + vga_ram_size;
242
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
243
    printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
244
    ret = load_image(buf, phys_ram_base + bios_offset);
245
    if (ret != BIOS_SIZE) {
246
        fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
247
        exit(1);
248
    }
249
    cpu_register_physical_memory((uint32_t)(0x1fc00000),
250
                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
251
#if 0
252
    memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
253
    cpu_single_env->PC = 0x80010004;
254
#else
255
    cpu_single_env->PC = 0xBFC00004;
256
#endif
257
    if (linux_boot) {
258
        kernel_base = KERNEL_LOAD_ADDR;
259
        /* now we can load the kernel */
260
        kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
261
        if (kernel_size < 0) {
262
            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
263
                    kernel_filename);
264
            exit(1);
265
        }
266
        /* load initrd */
267
        if (initrd_filename) {
268
            initrd_base = INITRD_LOAD_ADDR;
269
            initrd_size = load_image(initrd_filename,
270
                                     phys_ram_base + initrd_base);
271
            if (initrd_size < 0) {
272
                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
273
                        initrd_filename);
274
                exit(1);
275
            }
276
        } else {
277
            initrd_base = 0;
278
            initrd_size = 0;
279
        }
280
        cpu_single_env->PC = KERNEL_LOAD_ADDR;
281
    } else {
282
        kernel_base = 0;
283
        kernel_size = 0;
284
        initrd_base = 0;
285
        initrd_size = 0;
286
    }
287
    /* XXX: should not be ! */
288
    printf("%s: init VGA\n", __func__);
289
    vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, 
290
                   vga_ram_size);
291

    
292

    
293
    /* Init internal devices */
294
    cpu_mips_clock_init(cpu_single_env);
295
    cpu_mips_irqctrl_init();
296

    
297
    isa_mem_base = 0x78000000;
298
    /* Register 64 KB of ISA IO space at random address */
299
    io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
300
    cpu_register_physical_memory(0x70000000, 0x00010000, io_memory);
301
    serial_init(0x3f8, 4, serial_hds[0]);
302
    printf("%s: done\n", __func__);
303
}
304

    
305
QEMUMachine mips_machine = {
306
    "mips",
307
    "mips r4k platform",
308
    mips_r4k_init,
309
};