/[gxemul]/trunk/src/promemul/dec_prom.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/promemul/dec_prom.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 19677 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


1 dpavlin 14 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 14 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 34 * $Id: dec_prom.c,v 1.11 2006/12/30 13:31:02 debug Exp $
29 dpavlin 14 *
30     * DECstation PROM emulation.
31 dpavlin 24 *
32     * Implementation note: Remember that only the lowest 32 bits of GPRs are
33     * actually valid when using dyntrans with e.g. R3000 CPUs.
34 dpavlin 14 */
35    
36     #include <stdio.h>
37     #include <stdlib.h>
38     #include <string.h>
39     #include <sys/types.h>
40     #include <sys/time.h>
41     #include <sys/resource.h>
42    
43     #include "console.h"
44     #include "cpu.h"
45     #include "cpu_mips.h"
46     #include "diskimage.h"
47     #include "machine.h"
48     #include "memory.h"
49     #include "misc.h"
50    
51     #include "dec_prom.h"
52     #include "dec_5100.h"
53     #include "dec_kn01.h"
54     #include "dec_kn02.h"
55     #include "dec_kn03.h"
56    
57    
58     extern int quiet_mode;
59    
60    
61     /*
62     * mem_readchar():
63     *
64     * Reads a byte from emulated RAM, using a MIPS register as a base address.
65     * (Helper function.)
66     */
67     static unsigned char mem_readchar(struct cpu *cpu, int regbase, int offset)
68 dpavlin 24 {
69 dpavlin 14 unsigned char ch;
70 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[regbase] +
71     offset, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
72 dpavlin 14 return ch;
73     }
74    
75    
76     /*
77     * dec_jumptable_func():
78     *
79     * The jumptable is located at the beginning of the PROM, at 0xbfc00000 + i*8,
80     * where i is the decimal function number. Many of these can be converted to
81     * an identical callback function.
82     *
83     * Return value is non-zero if the vector number was converted into a callback
84     * function number, otherwise 0.
85     *
86     * Vector (dec) Function
87     * 0x0 0 reset()
88     * 0x10 2 restart()
89     * 0x18 3 reinit()
90     * 0x30 6 open()
91     * 0x38 7 read()
92     * 0x58 11 lseek()
93     * 0x68 13 putchar()
94     * 0x88 17 printf()
95     * 0x108 33 getenv2()
96     */
97     int dec_jumptable_func(struct cpu *cpu, int vector)
98     {
99     int i;
100     static int file_opened = 0;
101     static int current_file_offset = 0;
102    
103     switch (vector) {
104     case 0x0: /* reset() */
105     /* TODO */
106     cpu->machine->exit_without_entering_debugger = 1;
107     cpu->running = 0;
108     break;
109     case 0x10: /* restart() */
110     /* TODO */
111     cpu->machine->exit_without_entering_debugger = 1;
112     cpu->running = 0;
113     break;
114     case 0x18: /* reinit() */
115     /* TODO */
116     cpu->machine->exit_without_entering_debugger = 1;
117     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
118     break;
119     case 0x30: /* open() */
120     /*
121     * TODO: This is just a hack to allow Sprite/pmax' bootblock
122     * code to load /vmsprite. The filename argument (in A0)
123     * is ignored, and a file handle value of 1 is returned.
124     */
125     if (file_opened) {
126     fatal("\ndec_jumptable_func(): opening more than one "
127     "file isn't supported yet.\n");
128     cpu->running = 0;
129     }
130     file_opened = 1;
131     cpu->cd.mips.gpr[MIPS_GPR_V0] = 1;
132     break;
133     case 0x38: /* read(handle, ptr, length) */
134     cpu->cd.mips.gpr[MIPS_GPR_V0] = -1;
135     if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) {
136     int disk_id = diskimage_bootdev(cpu->machine, NULL);
137     int res;
138     unsigned char *tmp_buf;
139    
140     tmp_buf = malloc(cpu->cd.mips.gpr[MIPS_GPR_A2]);
141     if (tmp_buf == NULL) {
142     fprintf(stderr, "[ *** Out of memory in "
143     "dec_prom.c, allocating %i bytes ]\n",
144     (int)cpu->cd.mips.gpr[MIPS_GPR_A2]);
145     break;
146     }
147    
148     res = diskimage_access(cpu->machine, disk_id,
149     DISKIMAGE_SCSI, 0, current_file_offset, tmp_buf,
150     cpu->cd.mips.gpr[MIPS_GPR_A2]);
151    
152     /* If the transfer was successful, transfer the data
153     to emulated memory: */
154     if (res) {
155     uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1];
156     store_buf(cpu, dst, (char *)tmp_buf,
157     cpu->cd.mips.gpr[MIPS_GPR_A2]);
158     cpu->cd.mips.gpr[MIPS_GPR_V0] =
159     cpu->cd.mips.gpr[MIPS_GPR_A2];
160     current_file_offset +=
161     cpu->cd.mips.gpr[MIPS_GPR_A2];
162     }
163    
164     free(tmp_buf);
165     }
166     break;
167     case 0x58: /* lseek(handle, offset[, whence]) */
168     /* TODO */
169     if (cpu->cd.mips.gpr[MIPS_GPR_A2] == 0)
170     current_file_offset = cpu->cd.mips.gpr[MIPS_GPR_A1];
171     else
172     fatal("WARNING! Unimplemented whence in "
173     "dec_jumptable_func()\n");
174     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
175     break;
176     case 0x68: /* putchar() */
177     console_putchar(cpu->machine->main_console_handle,
178     cpu->cd.mips.gpr[MIPS_GPR_A0]);
179     break;
180     case 0x88: /* printf() */
181     return 0x30;
182     case 0x108: /* getenv2() */
183     return 0x64;
184     default:
185     cpu_register_dump(cpu->machine, cpu, 1, 0x1);
186     printf("a0 points to: ");
187     for (i=0; i<40; i++) {
188     unsigned char ch = '\0';
189     cpu->memory_rw(cpu, cpu->mem,
190 dpavlin 24 (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch,
191 dpavlin 14 sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
192     if (ch >= ' ' && ch < 126)
193     printf("%c", ch);
194     else
195     printf("[%02x]", ch);
196     }
197     printf("\n");
198     fatal("PROM emulation: unimplemented JUMP TABLE vector "
199     "0x%x (decimal function %i)\n", vector, vector/8);
200     cpu->running = 0;
201     }
202    
203     return 0;
204     }
205    
206    
207     /*
208     * decstation_prom_emul():
209     *
210     * DECstation PROM emulation.
211     *
212     * Callback functions:
213     * 0x0c strcmp()
214     * 0x14 strlen()
215     * 0x24 getchar()
216     * 0x28 gets()
217     * 0x2c puts()
218     * 0x30 printf()
219     * 0x38 iopoll()
220     * 0x54 bootinit()
221     * 0x58 bootread()
222     * 0x64 getenv()
223     * 0x6c slot_address()
224     * 0x70 wbflush()
225     * 0x7c clear_cache()
226     * 0x80 getsysid()
227     * 0x84 getbitmap()
228     * 0x88 disableintr()
229     * 0x8c enableintr()
230     * 0x9c halt()
231     * 0xa4 gettcinfo()
232     * 0xa8 execute_cmd()
233     * 0xac rex()
234     */
235     int decstation_prom_emul(struct cpu *cpu)
236     {
237     int i, j, ch, argreg, argdata;
238     int vector = cpu->pc & 0xfff;
239     int callback = (cpu->pc & 0xf000)? 1 : 0;
240     unsigned char buf[100];
241     unsigned char ch1, ch2, ch3;
242     uint64_t tmpaddr, slot_base = 0x10000000, slot_size = 0;
243    
244     if (!callback) {
245     vector = dec_jumptable_func(cpu, vector);
246     if (vector == 0)
247     return 1;
248     } else {
249     /* Vector number is n*4, PC points to n*8. */
250     vector /= 2;
251     }
252    
253     switch (vector) {
254     case 0x0c: /* strcmp(): */
255     i = j = 0;
256     do {
257     ch1 = mem_readchar(cpu, MIPS_GPR_A0, i++);
258     ch2 = mem_readchar(cpu, MIPS_GPR_A1, j++);
259     } while (ch1 == ch2 && ch1 != '\0');
260    
261     /* If ch1=='\0', then strings are equal. */
262     if (ch1 == '\0')
263     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
264     if ((signed char)ch1 > (signed char)ch2)
265     cpu->cd.mips.gpr[MIPS_GPR_V0] = 1;
266     if ((signed char)ch1 < (signed char)ch2)
267     cpu->cd.mips.gpr[MIPS_GPR_V0] = -1;
268     break;
269     case 0x14: /* strlen(): */
270     i = 0;
271     do {
272     ch2 = mem_readchar(cpu, MIPS_GPR_A0, i++);
273     } while (ch2 != 0);
274     cpu->cd.mips.gpr[MIPS_GPR_V0] = i - 1;
275     break;
276     case 0x24: /* getchar() */
277     /* debug("[ DEC PROM getchar() ]\n"); */
278     cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar(
279     cpu->machine->main_console_handle);
280     break;
281     case 0x28: /* gets() */
282     /* debug("[ DEC PROM gets() ]\n"); */
283     tmpaddr = cpu->cd.mips.gpr[MIPS_GPR_A0];
284     i = 0;
285    
286     /* TODO: Make this not hang (block) the entire emulator */
287    
288     do {
289     while ((ch = console_readchar(
290     cpu->machine->main_console_handle)) < 1)
291     ;
292     if (ch == '\r')
293     ch = '\n';
294     ch2 = ch;
295    
296     if (ch == '\b') {
297     if (i > 0) {
298     console_putchar(cpu->machine->
299     main_console_handle, ch2);
300     console_putchar(cpu->machine->
301     main_console_handle, ' ');
302     console_putchar(cpu->machine->
303     main_console_handle, ch2);
304     }
305     } else
306     console_putchar(cpu->machine->
307     main_console_handle, ch2);
308    
309     fflush(stdout);
310    
311     if (ch == '\n') {
312     /* It seems that trailing newlines
313     are not included in the buffer. */
314     } else if (ch != '\b') {
315 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
316 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_A0] + i,
317     &ch2, sizeof(ch2), MEM_WRITE,
318     CACHE_DATA | NO_EXCEPTIONS);
319     i++;
320     } else {
321     if (i > 0)
322     i--;
323     }
324     } while (ch2 != '\n');
325    
326     /* Trailing nul-byte: */
327     ch2 = '\0';
328 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
329     cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch2, sizeof(ch2),
330     MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS);
331 dpavlin 14
332     /* Return the input argument: */
333     cpu->cd.mips.gpr[MIPS_GPR_V0] = cpu->cd.mips.gpr[MIPS_GPR_A0];
334     break;
335     case 0x2c: /* puts() */
336     i = 0;
337     while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0')
338     console_putchar(cpu->machine->main_console_handle, ch);
339     console_putchar(cpu->machine->main_console_handle, '\n');
340     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
341     break;
342     case 0x30: /* printf() */
343     if (cpu->machine->register_dump ||
344     cpu->machine->instruction_trace)
345     debug("PROM printf(0x%08lx): \n",
346     (long)cpu->cd.mips.gpr[MIPS_GPR_A0]);
347    
348     i = 0; ch = -1; argreg = MIPS_GPR_A1;
349     while (ch != '\0') {
350     char printfbuf[8000];
351 dpavlin 22 size_t x;
352 dpavlin 14
353     printfbuf[0] = printfbuf[sizeof(printfbuf)-1] = '\0';
354    
355     ch = mem_readchar(cpu, MIPS_GPR_A0, i++);
356     switch (ch) {
357     case '%':
358     ch = '0';
359     while (ch >= '0' && ch <= '9')
360     ch = mem_readchar(cpu,
361     MIPS_GPR_A0, i++);
362    
363     switch (ch) {
364     case '%':
365     strlcpy(printfbuf, "%%",
366     sizeof(printfbuf));
367     break;
368     case 'c':
369     case 'd':
370     case 's':
371     case 'x':
372     /* Get argument: */
373     if (argreg > MIPS_GPR_A3) {
374     #if 1
375     /* Linux booters seem to go
376     over the edge sometimes: */
377     ch = '\0';
378     strlcpy(printfbuf, "[...]\n",
379     sizeof(printfbuf));
380     #else
381     printf("[ decstation_prom_emul"
382     "(): too many arguments ]");
383     /* This reuses the last arg,
384     which is utterly incorrect.
385     (TODO) */
386     argreg = MIPS_GPR_A3;
387     #endif
388     }
389    
390     ch2 = argdata =
391     cpu->cd.mips.gpr[argreg];
392    
393     switch (ch) {
394     case 'c':
395     snprintf(printfbuf, sizeof(
396     printfbuf), "%c", ch2);
397     break;
398     case 'd':
399     snprintf(printfbuf, sizeof(
400     printfbuf), "%d", argdata);
401     break;
402     case 'x':
403     snprintf(printfbuf, sizeof(
404     printfbuf), "%x", argdata);
405     break;
406     case 's':
407     /* Print a "%s" string. */
408     j = 0; ch3 = '\n';
409     while (ch2) {
410     ch2 = mem_readchar(cpu,
411     argreg, j++);
412     if (ch2) {
413     snprintf(
414     printfbuf +
415     strlen(
416     printfbuf),
417     sizeof(
418     printfbuf)-
419     1-strlen(
420     printfbuf),
421     "%c", ch2);
422     ch3 = ch2;
423     }
424     }
425     break;
426     }
427     argreg ++;
428     break;
429     default:
430     printf("[ unknown printf format char"
431     " '%c' ]", ch);
432     }
433     break;
434     case '\0':
435     break;
436     default:
437     snprintf(printfbuf, sizeof(printfbuf),
438     "%c", ch);
439     }
440    
441     printfbuf[sizeof(printfbuf)-1] = '\0';
442    
443     for (x=0; x<strlen(printfbuf); x++)
444     console_putchar(cpu->machine->
445     main_console_handle, printfbuf[x]);
446     }
447     if (cpu->machine->register_dump ||
448     cpu->machine->instruction_trace)
449     debug("\n");
450     fflush(stdout);
451     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
452     break;
453     case 0x54: /* bootinit() */
454     /* debug("[ DEC PROM bootinit(0x%08x): TODO ]\n",
455     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); */
456     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
457     break;
458     case 0x58: /* bootread(int b, void *buffer, int n) */
459     /*
460     * Read data from the boot device.
461     * b is a sector number (512 bytes per sector),
462     * buffer is the destination address, and n
463     * is the number of _bytes_ to read.
464     *
465     * TODO: Return value? NetBSD thinks that 0 is ok.
466     */
467     debug("[ DEC PROM bootread(0x%x, 0x%08x, 0x%x) ]\n",
468     (int)cpu->cd.mips.gpr[MIPS_GPR_A0],
469     (int)cpu->cd.mips.gpr[MIPS_GPR_A1],
470     (int)cpu->cd.mips.gpr[MIPS_GPR_A2]);
471    
472     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
473    
474     if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) {
475     int disk_id = diskimage_bootdev(cpu->machine, NULL);
476     int res;
477     unsigned char *tmp_buf;
478    
479     tmp_buf = malloc(cpu->cd.mips.gpr[MIPS_GPR_A2]);
480     if (tmp_buf == NULL) {
481     fprintf(stderr, "[ *** Out of memory in "
482     "dec_prom.c, allocating %i bytes ]\n",
483     (int)cpu->cd.mips.gpr[MIPS_GPR_A2]);
484     break;
485     }
486    
487     res = diskimage_access(cpu->machine, disk_id,
488     DISKIMAGE_SCSI, 0,
489     cpu->cd.mips.gpr[MIPS_GPR_A0] * 512, tmp_buf,
490     cpu->cd.mips.gpr[MIPS_GPR_A2]);
491    
492     /* If the transfer was successful, transfer the data
493     to emulated memory: */
494     if (res) {
495     uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1];
496     if (dst < 0x80000000ULL)
497     dst |= 0x80000000;
498    
499     store_buf(cpu, dst, (char *)tmp_buf,
500     cpu->cd.mips.gpr[MIPS_GPR_A2]);
501     cpu->cd.mips.gpr[MIPS_GPR_V0] =
502     cpu->cd.mips.gpr[MIPS_GPR_A2];
503     }
504    
505     free(tmp_buf);
506     }
507     break;
508     case 0x64: /* getenv() */
509     /* Find the environment variable given by a0: */
510 dpavlin 22 for (i=0; i<(int)sizeof(buf); i++)
511 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
512 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf[i],
513     sizeof(char), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
514     buf[sizeof(buf)-1] = '\0';
515     debug("[ DEC PROM getenv(\"%s\") ]\n", buf);
516     for (i=0; i<0x1000; i++) {
517     /* Matching string at offset i? */
518     int nmatches = 0;
519 dpavlin 22 for (j=0; j<(int32_t)strlen((char *)buf); j++) {
520 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
521 dpavlin 14 (DEC_PROM_STRINGS + i + j), &ch2,
522     sizeof(char), MEM_READ, CACHE_DATA |
523     NO_EXCEPTIONS);
524     if (ch2 == buf[j])
525     nmatches++;
526     }
527 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)(DEC_PROM_STRINGS
528 dpavlin 14 + i + strlen((char *)buf)), &ch2, sizeof(char),
529     MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
530 dpavlin 22 if (nmatches == (int)strlen((char *)buf) && ch2=='=') {
531 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_V0] =
532     DEC_PROM_STRINGS + i +
533     strlen((char *)buf) + 1;
534     return 1;
535     }
536     }
537     /* Return NULL if string wasn't found. */
538     fatal("[ DEC PROM getenv(\"%s\"): WARNING: Not in "
539     "environment! ]\n", buf);
540     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
541     break;
542     case 0x6c: /* ulong slot_address(int sn) */
543     debug("[ DEC PROM slot_address(%i) ]\n",
544     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]);
545     /* TODO: This is too hardcoded. */
546     /* TODO 2: Should these be physical or virtual addresses? */
547     switch (cpu->machine->machine_subtype) {
548     case MACHINE_DEC_3MAX_5000:
549     slot_base = KN02_PHYS_TC_0_START;/* 0x1e000000 */
550     slot_size = 4*1048576; /* 4 MB */
551     break;
552     case MACHINE_DEC_3MIN_5000:
553     slot_base = 0x10000000;
554     slot_size = 0x4000000; /* 64 MB */
555     break;
556     case MACHINE_DEC_3MAXPLUS_5000:
557     slot_base = 0x1e000000;
558     slot_size = 0x800000; /* 8 MB */
559     break;
560     case MACHINE_DEC_MAXINE_5000:
561     slot_base = 0x10000000;
562     slot_size = 0x4000000; /* 64 MB */
563     break;
564     default:
565     fatal("warning: DEC PROM slot_address() "
566     "unimplemented for this machine type\n");
567     }
568     cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t)
569     (0x80000000 + slot_base + slot_size *
570     cpu->cd.mips.gpr[MIPS_GPR_A0]);
571     break;
572     case 0x70: /* wbflush() */
573     debug("[ DEC PROM wbflush(): TODO ]\n");
574     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
575     break;
576     case 0x7c: /* clear_cache(addr, len) */
577     debug("[ DEC PROM clear_cache(0x%x,%i) ]\n",
578     (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0],
579     (int)cpu->cd.mips.gpr[MIPS_GPR_A1]);
580     /* TODO */
581     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* ? */
582     break;
583     case 0x80: /* getsysid() */
584     /* debug("[ DEC PROM getsysid() ]\n"); */
585     /* TODO: why did I add the 0x82 stuff??? */
586     cpu->cd.mips.gpr[MIPS_GPR_V0] = ((uint32_t)0x82 << 24)
587     + (cpu->machine->machine_subtype << 16) + (0x3 << 8);
588     cpu->cd.mips.gpr[MIPS_GPR_V0] =
589     (int64_t)(int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0];
590     break;
591     case 0x84: /* getbitmap() */
592     debug("[ DEC PROM getbitmap(0x%08x) ]\n",
593     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]);
594     store_buf(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0],
595 dpavlin 24 (char *)cpu->machine->md.pmax.memmap,
596     sizeof(struct dec_memmap));
597     cpu->cd.mips.gpr[MIPS_GPR_V0] =
598     sizeof(cpu->machine->md.pmax.memmap->bitmap);
599 dpavlin 14 break;
600     case 0x88: /* disableintr() */
601     debug("[ DEC PROM disableintr(): TODO ]\n");
602     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
603     break;
604     case 0x8c: /* enableintr() */
605     debug("[ DEC PROM enableintr(): TODO ]\n");
606     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
607     break;
608     case 0x9c: /* halt() */
609     debug("[ DEC PROM halt() ]\n");
610     cpu->machine->exit_without_entering_debugger = 1;
611     cpu->running = 0;
612     break;
613     case 0xa4: /* gettcinfo() */
614     /*
615     * These are just bogus values... TODO
616     *
617     * 0: revision
618     * 4: clock period in nano seconds
619     * 8: slot size in megabytes TODO: not same for all models!
620     * 12: I/O timeout in cycles
621     * 16: DMA address range in megabytes
622     * 20: maximum DMA burst length
623     * 24: turbochannel parity (yes = 1)
624     * 28: reserved
625     */
626     store_32bit_word(cpu, DEC_PROM_TCINFO + 0, 0);
627     store_32bit_word(cpu, DEC_PROM_TCINFO + 4, 50);
628     store_32bit_word(cpu, DEC_PROM_TCINFO + 8, 4);
629     store_32bit_word(cpu, DEC_PROM_TCINFO + 12, 10);
630     store_32bit_word(cpu, DEC_PROM_TCINFO + 16, 1);
631     store_32bit_word(cpu, DEC_PROM_TCINFO + 20, 100);
632     store_32bit_word(cpu, DEC_PROM_TCINFO + 24, 0);
633     store_32bit_word(cpu, DEC_PROM_TCINFO + 28, 0);
634     cpu->cd.mips.gpr[MIPS_GPR_V0] = DEC_PROM_TCINFO;
635     break;
636     case 0xa8: /* int execute_cmd(char *) */
637     i = 0;
638     while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0')
639     console_putchar(cpu->machine->main_console_handle, ch);
640     console_putchar(cpu->machine->main_console_handle, '\n');
641     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
642     break;
643     case 0xac: /* rex() */
644     debug("[ DEC PROM rex('%c') ]\n",
645     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]);
646 dpavlin 24 switch ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0]) {
647 dpavlin 14 case 'h':
648     debug("DEC PROM: rex('h') ==> halt\n");
649     cpu->machine->exit_without_entering_debugger = 1;
650     cpu->running = 0;
651     break;
652     case 'b':
653     debug("DEC PROM: rex('b') ==> reboot: TODO "
654     "(halting CPU instead)\n");
655     cpu->machine->exit_without_entering_debugger = 1;
656     cpu->running = 0;
657     break;
658     default:
659 dpavlin 24 fatal("DEC prom emulation: unknown rex() a0=0x%"PRIx64
660     " ('%c')\n",
661     (int64_t) cpu->cd.mips.gpr[MIPS_GPR_A0],
662     (char) cpu->cd.mips.gpr[MIPS_GPR_A0]);
663 dpavlin 14 cpu->running = 0;
664     }
665     break;
666     default:
667     cpu_register_dump(cpu->machine, cpu, 1, 0x1);
668     printf("a0 points to: ");
669     for (i=0; i<40; i++) {
670     unsigned char ch = '\0';
671 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
672 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch,
673     sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
674     if (ch >= ' ' && ch < 126)
675     printf("%c", ch);
676     else
677     printf("[%02x]", ch);
678     }
679     printf("\n");
680     fatal("PROM emulation: unimplemented callback vector 0x%x\n",
681     vector);
682     cpu->running = 0;
683     }
684    
685     return 1;
686     }
687    

  ViewVC Help
Powered by ViewVC 1.1.26