/[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 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 19833 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


1 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2003-2006 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 24 * $Id: dec_prom.c,v 1.9 2006/06/23 11:47:05 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     cpu->dead = 1;
109     break;
110     case 0x10: /* restart() */
111     /* TODO */
112     cpu->machine->exit_without_entering_debugger = 1;
113     cpu->running = 0;
114     cpu->dead = 1;
115     break;
116     case 0x18: /* reinit() */
117     /* TODO */
118     cpu->machine->exit_without_entering_debugger = 1;
119     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
120     break;
121     case 0x30: /* open() */
122     /*
123     * TODO: This is just a hack to allow Sprite/pmax' bootblock
124     * code to load /vmsprite. The filename argument (in A0)
125     * is ignored, and a file handle value of 1 is returned.
126     */
127     if (file_opened) {
128     fatal("\ndec_jumptable_func(): opening more than one "
129     "file isn't supported yet.\n");
130     cpu->running = 0;
131     cpu->dead = 1;
132     }
133     file_opened = 1;
134     cpu->cd.mips.gpr[MIPS_GPR_V0] = 1;
135     break;
136     case 0x38: /* read(handle, ptr, length) */
137     cpu->cd.mips.gpr[MIPS_GPR_V0] = -1;
138     if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) {
139     int disk_id = diskimage_bootdev(cpu->machine, NULL);
140     int res;
141     unsigned char *tmp_buf;
142    
143     tmp_buf = malloc(cpu->cd.mips.gpr[MIPS_GPR_A2]);
144     if (tmp_buf == NULL) {
145     fprintf(stderr, "[ *** Out of memory in "
146     "dec_prom.c, allocating %i bytes ]\n",
147     (int)cpu->cd.mips.gpr[MIPS_GPR_A2]);
148     break;
149     }
150    
151     res = diskimage_access(cpu->machine, disk_id,
152     DISKIMAGE_SCSI, 0, current_file_offset, tmp_buf,
153     cpu->cd.mips.gpr[MIPS_GPR_A2]);
154    
155     /* If the transfer was successful, transfer the data
156     to emulated memory: */
157     if (res) {
158     uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1];
159     store_buf(cpu, dst, (char *)tmp_buf,
160     cpu->cd.mips.gpr[MIPS_GPR_A2]);
161     cpu->cd.mips.gpr[MIPS_GPR_V0] =
162     cpu->cd.mips.gpr[MIPS_GPR_A2];
163     current_file_offset +=
164     cpu->cd.mips.gpr[MIPS_GPR_A2];
165     }
166    
167     free(tmp_buf);
168     }
169     break;
170     case 0x58: /* lseek(handle, offset[, whence]) */
171     /* TODO */
172     if (cpu->cd.mips.gpr[MIPS_GPR_A2] == 0)
173     current_file_offset = cpu->cd.mips.gpr[MIPS_GPR_A1];
174     else
175     fatal("WARNING! Unimplemented whence in "
176     "dec_jumptable_func()\n");
177     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
178     break;
179     case 0x68: /* putchar() */
180     console_putchar(cpu->machine->main_console_handle,
181     cpu->cd.mips.gpr[MIPS_GPR_A0]);
182     break;
183     case 0x88: /* printf() */
184     return 0x30;
185     case 0x108: /* getenv2() */
186     return 0x64;
187     default:
188     cpu_register_dump(cpu->machine, cpu, 1, 0x1);
189     printf("a0 points to: ");
190     for (i=0; i<40; i++) {
191     unsigned char ch = '\0';
192     cpu->memory_rw(cpu, cpu->mem,
193 dpavlin 24 (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch,
194 dpavlin 14 sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
195     if (ch >= ' ' && ch < 126)
196     printf("%c", ch);
197     else
198     printf("[%02x]", ch);
199     }
200     printf("\n");
201     fatal("PROM emulation: unimplemented JUMP TABLE vector "
202     "0x%x (decimal function %i)\n", vector, vector/8);
203     cpu->running = 0;
204     cpu->dead = 1;
205     }
206    
207     return 0;
208     }
209    
210    
211     /*
212     * decstation_prom_emul():
213     *
214     * DECstation PROM emulation.
215     *
216     * Callback functions:
217     * 0x0c strcmp()
218     * 0x14 strlen()
219     * 0x24 getchar()
220     * 0x28 gets()
221     * 0x2c puts()
222     * 0x30 printf()
223     * 0x38 iopoll()
224     * 0x54 bootinit()
225     * 0x58 bootread()
226     * 0x64 getenv()
227     * 0x6c slot_address()
228     * 0x70 wbflush()
229     * 0x7c clear_cache()
230     * 0x80 getsysid()
231     * 0x84 getbitmap()
232     * 0x88 disableintr()
233     * 0x8c enableintr()
234     * 0x9c halt()
235     * 0xa4 gettcinfo()
236     * 0xa8 execute_cmd()
237     * 0xac rex()
238     */
239     int decstation_prom_emul(struct cpu *cpu)
240     {
241     int i, j, ch, argreg, argdata;
242     int vector = cpu->pc & 0xfff;
243     int callback = (cpu->pc & 0xf000)? 1 : 0;
244     unsigned char buf[100];
245     unsigned char ch1, ch2, ch3;
246     uint64_t tmpaddr, slot_base = 0x10000000, slot_size = 0;
247    
248     if (!callback) {
249     vector = dec_jumptable_func(cpu, vector);
250     if (vector == 0)
251     return 1;
252     } else {
253     /* Vector number is n*4, PC points to n*8. */
254     vector /= 2;
255     }
256    
257     switch (vector) {
258     case 0x0c: /* strcmp(): */
259     i = j = 0;
260     do {
261     ch1 = mem_readchar(cpu, MIPS_GPR_A0, i++);
262     ch2 = mem_readchar(cpu, MIPS_GPR_A1, j++);
263     } while (ch1 == ch2 && ch1 != '\0');
264    
265     /* If ch1=='\0', then strings are equal. */
266     if (ch1 == '\0')
267     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
268     if ((signed char)ch1 > (signed char)ch2)
269     cpu->cd.mips.gpr[MIPS_GPR_V0] = 1;
270     if ((signed char)ch1 < (signed char)ch2)
271     cpu->cd.mips.gpr[MIPS_GPR_V0] = -1;
272     break;
273     case 0x14: /* strlen(): */
274     i = 0;
275     do {
276     ch2 = mem_readchar(cpu, MIPS_GPR_A0, i++);
277     } while (ch2 != 0);
278     cpu->cd.mips.gpr[MIPS_GPR_V0] = i - 1;
279     break;
280     case 0x24: /* getchar() */
281     /* debug("[ DEC PROM getchar() ]\n"); */
282     cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar(
283     cpu->machine->main_console_handle);
284     break;
285     case 0x28: /* gets() */
286     /* debug("[ DEC PROM gets() ]\n"); */
287     tmpaddr = cpu->cd.mips.gpr[MIPS_GPR_A0];
288     i = 0;
289    
290     /* TODO: Make this not hang (block) the entire emulator */
291    
292     do {
293     while ((ch = console_readchar(
294     cpu->machine->main_console_handle)) < 1)
295     ;
296     if (ch == '\r')
297     ch = '\n';
298     ch2 = ch;
299    
300     if (ch == '\b') {
301     if (i > 0) {
302     console_putchar(cpu->machine->
303     main_console_handle, ch2);
304     console_putchar(cpu->machine->
305     main_console_handle, ' ');
306     console_putchar(cpu->machine->
307     main_console_handle, ch2);
308     }
309     } else
310     console_putchar(cpu->machine->
311     main_console_handle, ch2);
312    
313     fflush(stdout);
314    
315     if (ch == '\n') {
316     /* It seems that trailing newlines
317     are not included in the buffer. */
318     } else if (ch != '\b') {
319 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
320 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_A0] + i,
321     &ch2, sizeof(ch2), MEM_WRITE,
322     CACHE_DATA | NO_EXCEPTIONS);
323     i++;
324     } else {
325     if (i > 0)
326     i--;
327     }
328     } while (ch2 != '\n');
329    
330     /* Trailing nul-byte: */
331     ch2 = '\0';
332 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
333     cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch2, sizeof(ch2),
334     MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS);
335 dpavlin 14
336     /* Return the input argument: */
337     cpu->cd.mips.gpr[MIPS_GPR_V0] = cpu->cd.mips.gpr[MIPS_GPR_A0];
338     break;
339     case 0x2c: /* puts() */
340     i = 0;
341     while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0')
342     console_putchar(cpu->machine->main_console_handle, ch);
343     console_putchar(cpu->machine->main_console_handle, '\n');
344     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
345     break;
346     case 0x30: /* printf() */
347     if (cpu->machine->register_dump ||
348     cpu->machine->instruction_trace)
349     debug("PROM printf(0x%08lx): \n",
350     (long)cpu->cd.mips.gpr[MIPS_GPR_A0]);
351    
352     i = 0; ch = -1; argreg = MIPS_GPR_A1;
353     while (ch != '\0') {
354     char printfbuf[8000];
355 dpavlin 22 size_t x;
356 dpavlin 14
357     printfbuf[0] = printfbuf[sizeof(printfbuf)-1] = '\0';
358    
359     ch = mem_readchar(cpu, MIPS_GPR_A0, i++);
360     switch (ch) {
361     case '%':
362     ch = '0';
363     while (ch >= '0' && ch <= '9')
364     ch = mem_readchar(cpu,
365     MIPS_GPR_A0, i++);
366    
367     switch (ch) {
368     case '%':
369     strlcpy(printfbuf, "%%",
370     sizeof(printfbuf));
371     break;
372     case 'c':
373     case 'd':
374     case 's':
375     case 'x':
376     /* Get argument: */
377     if (argreg > MIPS_GPR_A3) {
378     #if 1
379     /* Linux booters seem to go
380     over the edge sometimes: */
381     ch = '\0';
382     strlcpy(printfbuf, "[...]\n",
383     sizeof(printfbuf));
384     #else
385     printf("[ decstation_prom_emul"
386     "(): too many arguments ]");
387     /* This reuses the last arg,
388     which is utterly incorrect.
389     (TODO) */
390     argreg = MIPS_GPR_A3;
391     #endif
392     }
393    
394     ch2 = argdata =
395     cpu->cd.mips.gpr[argreg];
396    
397     switch (ch) {
398     case 'c':
399     snprintf(printfbuf, sizeof(
400     printfbuf), "%c", ch2);
401     break;
402     case 'd':
403     snprintf(printfbuf, sizeof(
404     printfbuf), "%d", argdata);
405     break;
406     case 'x':
407     snprintf(printfbuf, sizeof(
408     printfbuf), "%x", argdata);
409     break;
410     case 's':
411     /* Print a "%s" string. */
412     j = 0; ch3 = '\n';
413     while (ch2) {
414     ch2 = mem_readchar(cpu,
415     argreg, j++);
416     if (ch2) {
417     snprintf(
418     printfbuf +
419     strlen(
420     printfbuf),
421     sizeof(
422     printfbuf)-
423     1-strlen(
424     printfbuf),
425     "%c", ch2);
426     ch3 = ch2;
427     }
428     }
429     break;
430     }
431     argreg ++;
432     break;
433     default:
434     printf("[ unknown printf format char"
435     " '%c' ]", ch);
436     }
437     break;
438     case '\0':
439     break;
440     default:
441     snprintf(printfbuf, sizeof(printfbuf),
442     "%c", ch);
443     }
444    
445     printfbuf[sizeof(printfbuf)-1] = '\0';
446    
447     for (x=0; x<strlen(printfbuf); x++)
448     console_putchar(cpu->machine->
449     main_console_handle, printfbuf[x]);
450     }
451     if (cpu->machine->register_dump ||
452     cpu->machine->instruction_trace)
453     debug("\n");
454     fflush(stdout);
455     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
456     break;
457     case 0x54: /* bootinit() */
458     /* debug("[ DEC PROM bootinit(0x%08x): TODO ]\n",
459     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); */
460     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
461     break;
462     case 0x58: /* bootread(int b, void *buffer, int n) */
463     /*
464     * Read data from the boot device.
465     * b is a sector number (512 bytes per sector),
466     * buffer is the destination address, and n
467     * is the number of _bytes_ to read.
468     *
469     * TODO: Return value? NetBSD thinks that 0 is ok.
470     */
471     debug("[ DEC PROM bootread(0x%x, 0x%08x, 0x%x) ]\n",
472     (int)cpu->cd.mips.gpr[MIPS_GPR_A0],
473     (int)cpu->cd.mips.gpr[MIPS_GPR_A1],
474     (int)cpu->cd.mips.gpr[MIPS_GPR_A2]);
475    
476     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
477    
478     if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) {
479     int disk_id = diskimage_bootdev(cpu->machine, NULL);
480     int res;
481     unsigned char *tmp_buf;
482    
483     tmp_buf = malloc(cpu->cd.mips.gpr[MIPS_GPR_A2]);
484     if (tmp_buf == NULL) {
485     fprintf(stderr, "[ *** Out of memory in "
486     "dec_prom.c, allocating %i bytes ]\n",
487     (int)cpu->cd.mips.gpr[MIPS_GPR_A2]);
488     break;
489     }
490    
491     res = diskimage_access(cpu->machine, disk_id,
492     DISKIMAGE_SCSI, 0,
493     cpu->cd.mips.gpr[MIPS_GPR_A0] * 512, tmp_buf,
494     cpu->cd.mips.gpr[MIPS_GPR_A2]);
495    
496     /* If the transfer was successful, transfer the data
497     to emulated memory: */
498     if (res) {
499     uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1];
500     if (dst < 0x80000000ULL)
501     dst |= 0x80000000;
502    
503     store_buf(cpu, dst, (char *)tmp_buf,
504     cpu->cd.mips.gpr[MIPS_GPR_A2]);
505     cpu->cd.mips.gpr[MIPS_GPR_V0] =
506     cpu->cd.mips.gpr[MIPS_GPR_A2];
507     }
508    
509     free(tmp_buf);
510     }
511     break;
512     case 0x64: /* getenv() */
513     /* Find the environment variable given by a0: */
514 dpavlin 22 for (i=0; i<(int)sizeof(buf); i++)
515 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
516 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf[i],
517     sizeof(char), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
518     buf[sizeof(buf)-1] = '\0';
519     debug("[ DEC PROM getenv(\"%s\") ]\n", buf);
520     for (i=0; i<0x1000; i++) {
521     /* Matching string at offset i? */
522     int nmatches = 0;
523 dpavlin 22 for (j=0; j<(int32_t)strlen((char *)buf); j++) {
524 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
525 dpavlin 14 (DEC_PROM_STRINGS + i + j), &ch2,
526     sizeof(char), MEM_READ, CACHE_DATA |
527     NO_EXCEPTIONS);
528     if (ch2 == buf[j])
529     nmatches++;
530     }
531 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)(DEC_PROM_STRINGS
532 dpavlin 14 + i + strlen((char *)buf)), &ch2, sizeof(char),
533     MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
534 dpavlin 22 if (nmatches == (int)strlen((char *)buf) && ch2=='=') {
535 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_V0] =
536     DEC_PROM_STRINGS + i +
537     strlen((char *)buf) + 1;
538     return 1;
539     }
540     }
541     /* Return NULL if string wasn't found. */
542     fatal("[ DEC PROM getenv(\"%s\"): WARNING: Not in "
543     "environment! ]\n", buf);
544     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
545     break;
546     case 0x6c: /* ulong slot_address(int sn) */
547     debug("[ DEC PROM slot_address(%i) ]\n",
548     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]);
549     /* TODO: This is too hardcoded. */
550     /* TODO 2: Should these be physical or virtual addresses? */
551     switch (cpu->machine->machine_subtype) {
552     case MACHINE_DEC_3MAX_5000:
553     slot_base = KN02_PHYS_TC_0_START;/* 0x1e000000 */
554     slot_size = 4*1048576; /* 4 MB */
555     break;
556     case MACHINE_DEC_3MIN_5000:
557     slot_base = 0x10000000;
558     slot_size = 0x4000000; /* 64 MB */
559     break;
560     case MACHINE_DEC_3MAXPLUS_5000:
561     slot_base = 0x1e000000;
562     slot_size = 0x800000; /* 8 MB */
563     break;
564     case MACHINE_DEC_MAXINE_5000:
565     slot_base = 0x10000000;
566     slot_size = 0x4000000; /* 64 MB */
567     break;
568     default:
569     fatal("warning: DEC PROM slot_address() "
570     "unimplemented for this machine type\n");
571     }
572     cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t)
573     (0x80000000 + slot_base + slot_size *
574     cpu->cd.mips.gpr[MIPS_GPR_A0]);
575     break;
576     case 0x70: /* wbflush() */
577     debug("[ DEC PROM wbflush(): TODO ]\n");
578     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
579     break;
580     case 0x7c: /* clear_cache(addr, len) */
581     debug("[ DEC PROM clear_cache(0x%x,%i) ]\n",
582     (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0],
583     (int)cpu->cd.mips.gpr[MIPS_GPR_A1]);
584     /* TODO */
585     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* ? */
586     break;
587     case 0x80: /* getsysid() */
588     /* debug("[ DEC PROM getsysid() ]\n"); */
589     /* TODO: why did I add the 0x82 stuff??? */
590     cpu->cd.mips.gpr[MIPS_GPR_V0] = ((uint32_t)0x82 << 24)
591     + (cpu->machine->machine_subtype << 16) + (0x3 << 8);
592     cpu->cd.mips.gpr[MIPS_GPR_V0] =
593     (int64_t)(int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0];
594     break;
595     case 0x84: /* getbitmap() */
596     debug("[ DEC PROM getbitmap(0x%08x) ]\n",
597     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]);
598     store_buf(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0],
599 dpavlin 24 (char *)cpu->machine->md.pmax.memmap,
600     sizeof(struct dec_memmap));
601     cpu->cd.mips.gpr[MIPS_GPR_V0] =
602     sizeof(cpu->machine->md.pmax.memmap->bitmap);
603 dpavlin 14 break;
604     case 0x88: /* disableintr() */
605     debug("[ DEC PROM disableintr(): TODO ]\n");
606     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
607     break;
608     case 0x8c: /* enableintr() */
609     debug("[ DEC PROM enableintr(): TODO ]\n");
610     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
611     break;
612     case 0x9c: /* halt() */
613     debug("[ DEC PROM halt() ]\n");
614     cpu->machine->exit_without_entering_debugger = 1;
615     cpu->running = 0;
616     cpu->dead = 1;
617     break;
618     case 0xa4: /* gettcinfo() */
619     /*
620     * These are just bogus values... TODO
621     *
622     * 0: revision
623     * 4: clock period in nano seconds
624     * 8: slot size in megabytes TODO: not same for all models!
625     * 12: I/O timeout in cycles
626     * 16: DMA address range in megabytes
627     * 20: maximum DMA burst length
628     * 24: turbochannel parity (yes = 1)
629     * 28: reserved
630     */
631     store_32bit_word(cpu, DEC_PROM_TCINFO + 0, 0);
632     store_32bit_word(cpu, DEC_PROM_TCINFO + 4, 50);
633     store_32bit_word(cpu, DEC_PROM_TCINFO + 8, 4);
634     store_32bit_word(cpu, DEC_PROM_TCINFO + 12, 10);
635     store_32bit_word(cpu, DEC_PROM_TCINFO + 16, 1);
636     store_32bit_word(cpu, DEC_PROM_TCINFO + 20, 100);
637     store_32bit_word(cpu, DEC_PROM_TCINFO + 24, 0);
638     store_32bit_word(cpu, DEC_PROM_TCINFO + 28, 0);
639     cpu->cd.mips.gpr[MIPS_GPR_V0] = DEC_PROM_TCINFO;
640     break;
641     case 0xa8: /* int execute_cmd(char *) */
642     i = 0;
643     while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0')
644     console_putchar(cpu->machine->main_console_handle, ch);
645     console_putchar(cpu->machine->main_console_handle, '\n');
646     cpu->cd.mips.gpr[MIPS_GPR_V0] = 0;
647     break;
648     case 0xac: /* rex() */
649     debug("[ DEC PROM rex('%c') ]\n",
650     (int)cpu->cd.mips.gpr[MIPS_GPR_A0]);
651 dpavlin 24 switch ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0]) {
652 dpavlin 14 case 'h':
653     debug("DEC PROM: rex('h') ==> halt\n");
654     cpu->machine->exit_without_entering_debugger = 1;
655     cpu->running = 0;
656     cpu->dead = 1;
657     break;
658     case 'b':
659     debug("DEC PROM: rex('b') ==> reboot: TODO "
660     "(halting CPU instead)\n");
661     cpu->machine->exit_without_entering_debugger = 1;
662     cpu->running = 0;
663     cpu->dead = 1;
664     break;
665     default:
666 dpavlin 24 fatal("DEC prom emulation: unknown rex() a0=0x%"PRIx64
667     " ('%c')\n",
668     (int64_t) cpu->cd.mips.gpr[MIPS_GPR_A0],
669     (char) cpu->cd.mips.gpr[MIPS_GPR_A0]);
670 dpavlin 14 cpu->running = 0;
671     cpu->dead = 1;
672     }
673     break;
674     default:
675     cpu_register_dump(cpu->machine, cpu, 1, 0x1);
676     printf("a0 points to: ");
677     for (i=0; i<40; i++) {
678     unsigned char ch = '\0';
679 dpavlin 24 cpu->memory_rw(cpu, cpu->mem, (int32_t)
680 dpavlin 14 cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch,
681     sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
682     if (ch >= ' ' && ch < 126)
683     printf("%c", ch);
684     else
685     printf("[%02x]", ch);
686     }
687     printf("\n");
688     fatal("PROM emulation: unimplemented callback vector 0x%x\n",
689     vector);
690     cpu->running = 0;
691     cpu->dead = 1;
692     }
693    
694     return 1;
695     }
696    

  ViewVC Help
Powered by ViewVC 1.1.26