added NE2000 (Ralf Baechle)
[qemu] / hw / mips_r4k.c
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 uint32_t cpu_mips_get_random (CPUState *env)
82 {
83     uint32_t now = qemu_get_clock(vm_clock);
84
85     return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
86 }
87
88 /* MIPS R4K timer */
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,
261                                 phys_ram_base + (kernel_base - 0x80000000));
262         if (kernel_size == (target_ulong) -1) {
263             fprintf(stderr, "qemu: could not load kernel '%s'\n", 
264                     kernel_filename);
265             exit(1);
266         }
267         /* load initrd */
268         if (initrd_filename) {
269             initrd_base = INITRD_LOAD_ADDR;
270             initrd_size = load_image(initrd_filename,
271                                      phys_ram_base + initrd_base);
272             if (initrd_size == (target_ulong) -1) {
273                 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
274                         initrd_filename);
275                 exit(1);
276             }
277         } else {
278             initrd_base = 0;
279             initrd_size = 0;
280         }
281         cpu_single_env->PC = KERNEL_LOAD_ADDR;
282     } else {
283         kernel_base = 0;
284         kernel_size = 0;
285         initrd_base = 0;
286         initrd_size = 0;
287     }
288
289     /* Init internal devices */
290     cpu_mips_clock_init(cpu_single_env);
291     cpu_mips_irqctrl_init();
292
293     /* Register 64 KB of ISA IO space at 0x14000000 */
294     io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
295     cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
296     isa_mem_base = 0x10000000;
297
298     serial_init(0x3f8, 4, serial_hds[0]);
299     vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, 
300                    vga_ram_size);
301
302     isa_ne2000_init(0x300, 9, &nd_table[0]);
303 }
304
305 QEMUMachine mips_machine = {
306     "mips",
307     "mips r4k platform",
308     mips_r4k_init,
309 };