/[gxemul]/trunk/src/cpus/cpu_alpha.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

Contents of /trunk/src/cpus/cpu_alpha.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 20154 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 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
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 * $Id: cpu_alpha.c,v 1.16 2006/06/16 18:31:25 debug Exp $
29 *
30 * Alpha CPU emulation.
31 *
32 * TODO: Many things.
33 *
34 * See http://www.eecs.harvard.edu/~nr/toolkit/specs/alpha.html for info
35 * on instruction formats etc.
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42
43 #include "cpu.h"
44 #include "machine.h"
45 #include "memory.h"
46 #include "misc.h"
47 #include "symbol.h"
48
49 #define DYNTRANS_8K
50 #define DYNTRANS_PAGESIZE 8192
51 #include "tmp_alpha_head.c"
52
53
54 /* Alpha symbolic register names: */
55 static char *alpha_regname[N_ALPHA_REGS] = ALPHA_REG_NAMES;
56
57
58 /*
59 * alpha_cpu_new():
60 *
61 * Create a new Alpha CPU object by filling the CPU struct.
62 * Return 1 on success, 0 if cpu_type_name isn't a valid Alpha processor.
63 */
64 int alpha_cpu_new(struct cpu *cpu, struct memory *mem,
65 struct machine *machine, int cpu_id, char *cpu_type_name)
66 {
67 int i = 0;
68 struct alpha_cpu_type_def cpu_type_defs[] = ALPHA_CPU_TYPE_DEFS;
69
70 /* Scan the cpu_type_defs list for this cpu type: */
71 while (cpu_type_defs[i].name != NULL) {
72 if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
73 break;
74 }
75 i++;
76 }
77 if (cpu_type_defs[i].name == NULL)
78 return 0;
79
80 cpu->memory_rw = alpha_memory_rw;
81 cpu->translate_address = alpha_translate_address;
82 cpu->update_translation_table = alpha_update_translation_table;
83 cpu->invalidate_translation_caches =
84 alpha_invalidate_translation_caches;
85 cpu->invalidate_code_translation = alpha_invalidate_code_translation;
86 cpu->is_32bit = 0;
87
88 /* Only show name and caches etc for CPU nr 0: */
89 if (cpu_id == 0) {
90 debug("%s", cpu->name);
91 }
92
93 cpu->cd.alpha.r[ALPHA_SP] = 0xfffffc000000ff00ULL;
94
95 alpha_init_64bit_dummy_tables(cpu);
96
97 return 1;
98 }
99
100
101 /*
102 * alpha_cpu_dumpinfo():
103 */
104 void alpha_cpu_dumpinfo(struct cpu *cpu)
105 {
106 /* TODO */
107 debug("\n");
108 }
109
110
111 /*
112 * alpha_cpu_list_available_types():
113 *
114 * Print a list of available Alpha CPU types.
115 */
116 void alpha_cpu_list_available_types(void)
117 {
118 int i, j;
119 struct alpha_cpu_type_def tdefs[] = ALPHA_CPU_TYPE_DEFS;
120
121 i = 0;
122 while (tdefs[i].name != NULL) {
123 debug("%s", tdefs[i].name);
124 for (j=16 - strlen(tdefs[i].name); j>0; j--)
125 debug(" ");
126 i++;
127 if ((i % 4) == 0 || tdefs[i].name == NULL)
128 debug("\n");
129 }
130 }
131
132
133 /*
134 * alpha_cpu_register_match():
135 */
136 void alpha_cpu_register_match(struct machine *m, char *name,
137 int writeflag, uint64_t *valuep, int *match_register)
138 {
139 int i, cpunr = 0;
140
141 /* CPU number: */
142
143 /* TODO */
144
145 if (strcasecmp(name, "pc") == 0) {
146 if (writeflag) {
147 m->cpus[cpunr]->pc = *valuep;
148 } else
149 *valuep = m->cpus[cpunr]->pc;
150 *match_register = 1;
151 }
152
153 /* Register names: */
154 for (i=0; i<N_ALPHA_REGS; i++) {
155 if (strcasecmp(name, alpha_regname[i]) == 0) {
156 if (writeflag)
157 m->cpus[cpunr]->cd.alpha.r[i] = *valuep;
158 else
159 *valuep = m->cpus[cpunr]->cd.alpha.r[i];
160 *match_register = 1;
161 }
162 }
163 }
164
165
166 /*
167 * alpha_cpu_register_dump():
168 *
169 * Dump cpu registers in a relatively readable format.
170 *
171 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
172 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
173 */
174 void alpha_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
175 {
176 char *symbol;
177 uint64_t offset;
178 int i, x = cpu->cpu_id;
179
180 if (gprs) {
181 symbol = get_symbol_name(&cpu->machine->symbol_context,
182 cpu->pc, &offset);
183 debug("cpu%i:\t pc = 0x%016"PRIx64, x, (uint64_t) cpu->pc);
184 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
185 for (i=0; i<N_ALPHA_REGS; i++) {
186 int r = (i >> 1) + ((i & 1) << 4);
187 if ((i % 2) == 0)
188 debug("cpu%i:\t", x);
189 if (r != ALPHA_ZERO)
190 debug("%3s = 0x%016"PRIx64, alpha_regname[r],
191 (uint64_t) cpu->cd.alpha.r[r]);
192 debug((i % 2) == 1? "\n" : " ");
193 }
194 }
195 }
196
197
198 /*
199 * alpha_cpu_tlbdump():
200 *
201 * Called from the debugger to dump the TLB in a readable format.
202 * x is the cpu number to dump, or -1 to dump all CPUs.
203 *
204 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
205 * just dumped.
206 */
207 void alpha_cpu_tlbdump(struct machine *m, int x, int rawflag)
208 {
209 }
210
211
212 static void add_response_word(struct cpu *cpu, char *r, uint64_t value,
213 size_t maxlen, int len)
214 {
215 char *format = (len == 4)? "%08"PRIx64 : "%016"PRIx64;
216 if (len == 4)
217 value &= 0xffffffffULL;
218 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
219 if (len == 4) {
220 value = ((value & 0xff) << 24) +
221 ((value & 0xff00) << 8) +
222 ((value & 0xff0000) >> 8) +
223 ((value & 0xff000000) >> 24);
224 } else {
225 value = ((value & 0xff) << 56) +
226 ((value & 0xff00) << 40) +
227 ((value & 0xff0000) << 24) +
228 ((value & 0xff000000ULL) << 8) +
229 ((value & 0xff00000000ULL) >> 8) +
230 ((value & 0xff0000000000ULL) >> 24) +
231 ((value & 0xff000000000000ULL) >> 40) +
232 ((value & 0xff00000000000000ULL) >> 56);
233 }
234 }
235 snprintf(r + strlen(r), maxlen - strlen(r), format, (uint64_t)value);
236 }
237
238
239 /*
240 * alpha_cpu_gdb_stub():
241 *
242 * Execute a "remote GDB" command. Returns a newly allocated response string
243 * on success, NULL on failure.
244 */
245 char *alpha_cpu_gdb_stub(struct cpu *cpu, char *cmd)
246 {
247 if (strcmp(cmd, "g") == 0) {
248 int i;
249 char *r;
250 size_t wlen = cpu->is_32bit?
251 sizeof(uint32_t) : sizeof(uint64_t);
252 size_t len = 1 + 76 * wlen;
253 r = malloc(len);
254 if (r == NULL) {
255 fprintf(stderr, "out of memory\n");
256 exit(1);
257 }
258 r[0] = '\0';
259 for (i=0; i<128; i++)
260 add_response_word(cpu, r, i, len, wlen);
261 return r;
262 }
263
264 if (cmd[0] == 'p') {
265 int regnr = strtol(cmd + 1, NULL, 16);
266 size_t wlen = cpu->is_32bit?
267 sizeof(uint32_t) : sizeof(uint64_t);
268 size_t len = 2 * wlen + 1;
269 char *r = malloc(len);
270 r[0] = '\0';
271 if (regnr >= 0 && regnr <= 31) {
272 add_response_word(cpu, r,
273 cpu->cd.alpha.r[regnr], len, wlen);
274 } else if (regnr >= 32 && regnr <= 62) {
275 add_response_word(cpu, r,
276 cpu->cd.alpha.f[regnr - 32], len, wlen);
277 } else if (regnr == 0x3f) {
278 add_response_word(cpu, r, cpu->cd.alpha.fpcr,
279 len, wlen);
280 } else if (regnr == 0x40) {
281 add_response_word(cpu, r, cpu->pc, len, wlen);
282 } else {
283 /* Unimplemented: */
284 add_response_word(cpu, r, 0xcc000 + regnr, len, wlen);
285 }
286 return r;
287 }
288
289 fatal("alpha_cpu_gdb_stub(): TODO\n");
290 return NULL;
291 }
292
293
294 /*
295 * alpha_cpu_interrupt():
296 */
297 int alpha_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
298 {
299 fatal("alpha_cpu_interrupt(): TODO\n");
300 return 0;
301 }
302
303
304 /*
305 * alpha_cpu_interrupt_ack():
306 */
307 int alpha_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
308 {
309 /* fatal("alpha_cpu_interrupt_ack(): TODO\n"); */
310 return 0;
311 }
312
313
314 /*
315 * alpha_print_imm16_disp():
316 *
317 * Used internally by alpha_cpu_disassemble_instr().
318 */
319 static void alpha_print_imm16_disp(int imm, int rb)
320 {
321 imm = (int16_t)imm;
322
323 if (imm < 0) {
324 debug("-");
325 imm = -imm;
326 }
327 if (imm <= 256)
328 debug("%i", imm);
329 else
330 debug("0x%x", imm);
331 if (rb != ALPHA_ZERO)
332 debug("(%s)", alpha_regname[rb]);
333 }
334
335
336 /*
337 * alpha_cpu_disassemble_instr():
338 *
339 * Convert an instruction word into human readable format, for instruction
340 * tracing.
341 *
342 * If running is 1, cpu->pc should be the address of the instruction.
343 *
344 * If running is 0, things that depend on the runtime environment (eg.
345 * register contents) will not be shown, and addr will be used instead of
346 * cpu->pc for relative addresses.
347 */
348 int alpha_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
349 int running, uint64_t dumpaddr)
350 {
351 uint32_t iw;
352 uint64_t offset, tmp;
353 int opcode, ra, rb, func, rc, imm, floating, rbrc = 0, indir = 0;
354 char *symbol, *mnem = NULL;
355 char palcode_name[30];
356
357 if (running)
358 dumpaddr = cpu->pc;
359
360 symbol = get_symbol_name(&cpu->machine->symbol_context,
361 dumpaddr, &offset);
362 if (symbol != NULL && offset == 0)
363 debug("<%s>\n", symbol);
364
365 if (cpu->machine->ncpus > 1 && running)
366 debug("cpu%i:\t", cpu->cpu_id);
367
368 debug("%016"PRIx64": ", (uint64_t) dumpaddr);
369
370 iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
371 debug("%08x\t", (int)iw);
372
373 opcode = iw >> 26;
374 ra = (iw >> 21) & 31;
375 rb = (iw >> 16) & 31;
376 func = (iw >> 5) & 0x7ff;
377 rc = iw & 31;
378 imm = iw & 0xffff;
379
380 switch (opcode) {
381 case 0x00:
382 alpha_palcode_name(iw & 0x3ffffff, palcode_name,
383 sizeof(palcode_name));
384 debug("call_pal %s\n", palcode_name);
385 break;
386 case 0x08:
387 case 0x09:
388 debug("lda%s\t%s,", opcode == 9? "h" : "", alpha_regname[ra]);
389 alpha_print_imm16_disp(imm, rb);
390 debug("\n");
391 break;
392 case 0x0a:
393 case 0x0b:
394 case 0x0c:
395 case 0x0d:
396 case 0x0e:
397 case 0x0f:
398 case 0x20:
399 case 0x21:
400 case 0x22:
401 case 0x23:
402 case 0x24:
403 case 0x25:
404 case 0x26:
405 case 0x27:
406 case 0x28:
407 case 0x29:
408 case 0x2a:
409 case 0x2b:
410 case 0x2c:
411 case 0x2d:
412 case 0x2e:
413 case 0x2f:
414 floating = 0;
415 switch (opcode) {
416 case 0x0a: mnem = "ldbu"; break;
417 case 0x0b: mnem = "ldq_u"; break;
418 case 0x0c: mnem = "ldwu"; break;
419 case 0x0d: mnem = "stw"; break;
420 case 0x0e: mnem = "stb"; break;
421 case 0x0f: mnem = "stq_u"; break;
422 case 0x20: mnem = "ldf"; floating = 1; break;
423 case 0x21: mnem = "ldg"; floating = 1; break;
424 case 0x22: mnem = "lds"; floating = 1; break;
425 case 0x23: mnem = "ldt"; floating = 1; break;
426 case 0x24: mnem = "stf"; floating = 1; break;
427 case 0x25: mnem = "stg"; floating = 1; break;
428 case 0x26: mnem = "sts"; floating = 1; break;
429 case 0x27: mnem = "stt"; floating = 1; break;
430 case 0x28: mnem = "ldl"; break;
431 case 0x29: mnem = "ldq"; break;
432 case 0x2a: mnem = "ldl_l"; break;
433 case 0x2b: mnem = "ldq_l"; break;
434 case 0x2c: mnem = "stl"; break;
435 case 0x2d: mnem = "stq"; break;
436 case 0x2e: mnem = "stl_c"; break;
437 case 0x2f: mnem = "stq_c"; break;
438 }
439 if (opcode == 0x0b && ra == ALPHA_ZERO) {
440 debug("unop");
441 } else {
442 debug("%s\t", mnem);
443 if (floating)
444 debug("f%i,", ra);
445 else
446 debug("%s,", alpha_regname[ra]);
447 alpha_print_imm16_disp(imm, rb);
448 }
449 debug("\n");
450 break;
451 case 0x10:
452 switch (func & 0x7f) {
453 case 0x00: mnem = "addl"; break;
454 case 0x02: mnem = "s4addl"; break;
455 case 0x09: mnem = "subl"; break;
456 case 0x0b: mnem = "s4subl"; break;
457 case 0x0f: mnem = "cmpbge"; break;
458 case 0x12: mnem = "s8addl"; break;
459 case 0x1b: mnem = "s8subl"; break;
460 case 0x1d: mnem = "cmpult"; break;
461 case 0x20: mnem = "addq"; break;
462 case 0x22: mnem = "s4addq"; break;
463 case 0x29: mnem = "subq"; break;
464 case 0x2b: mnem = "s4subq"; break;
465 case 0x2d: mnem = "cmpeq"; break;
466 case 0x32: mnem = "s8addq"; break;
467 case 0x3b: mnem = "s8subq"; break;
468 case 0x3d: mnem = "cmpule"; break;
469 case 0x40: mnem = "addl/v"; break;
470 case 0x49: mnem = "subl/v"; break;
471 case 0x4d: mnem = "cmplt"; break;
472 case 0x60: mnem = "addq/v"; break;
473 case 0x69: mnem = "subq/v"; break;
474 case 0x6d: mnem = "cmple"; break;
475 default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n",
476 opcode, func);
477 }
478 if (mnem == NULL)
479 break;
480 if (func & 0x80)
481 debug("%s\t%s,0x%x,%s\n", mnem,
482 alpha_regname[ra], (rb << 3) + (func >> 8),
483 alpha_regname[rc]);
484 else
485 debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra],
486 alpha_regname[rb], alpha_regname[rc]);
487 break;
488 case 0x11:
489 switch (func & 0x7f) {
490 case 0x000: mnem = "and"; break;
491 case 0x008: mnem = "andnot"; break;
492 case 0x014: mnem = "cmovlbs"; break;
493 case 0x016: mnem = "cmovlbc"; break;
494 case 0x020: mnem = "or"; break;
495 case 0x024: mnem = "cmoveq"; break;
496 case 0x026: mnem = "cmovne"; break;
497 case 0x028: mnem = "ornot"; break;
498 case 0x040: mnem = "xor"; break;
499 case 0x044: mnem = "cmovlt"; break;
500 case 0x046: mnem = "cmovge"; break;
501 case 0x048: mnem = "eqv"; break;
502 case 0x061: mnem = "amask"; break;
503 case 0x064: mnem = "cmovle"; break;
504 case 0x066: mnem = "cmovgt"; break;
505 default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n",
506 opcode, func);
507 }
508 if (mnem == NULL)
509 break;
510 /* Special cases: "nop" etc: */
511 if (func == 0x020 && rc == ALPHA_ZERO)
512 debug("nop\n");
513 else if (func == 0x020 && (ra == ALPHA_ZERO
514 || rb == ALPHA_ZERO)) {
515 if (ra == ALPHA_ZERO && rb == ALPHA_ZERO)
516 debug("clr\t%s\n", alpha_regname[rc]);
517 else if (ra == ALPHA_ZERO)
518 debug("mov\t%s,%s\n", alpha_regname[rb],
519 alpha_regname[rc]);
520 else
521 debug("mov\t%s,%s\n", alpha_regname[ra],
522 alpha_regname[rc]);
523 } else if (func & 0x80)
524 debug("%s\t%s,0x%x,%s\n", mnem,
525 alpha_regname[ra], (rb << 3) + (func >> 8),
526 alpha_regname[rc]);
527 else
528 debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra],
529 alpha_regname[rb], alpha_regname[rc]);
530 break;
531 case 0x12:
532 switch (func & 0x7f) {
533 case 0x02: mnem = "mskbl"; break;
534 case 0x06: mnem = "extbl"; break;
535 case 0x0b: mnem = "insbl"; break;
536 case 0x12: mnem = "mskwl"; break;
537 case 0x16: mnem = "extwl"; break;
538 case 0x1b: mnem = "inswl"; break;
539 case 0x22: mnem = "mskll"; break;
540 case 0x26: mnem = "extll"; break;
541 case 0x2b: mnem = "insll"; break;
542 case 0x30: mnem = "zap"; break;
543 case 0x31: mnem = "zapnot"; break;
544 case 0x32: mnem = "mskql"; break;
545 case 0x34: mnem = "srl"; break;
546 case 0x36: mnem = "extql"; break;
547 case 0x39: mnem = "sll"; break;
548 case 0x3b: mnem = "insql"; break;
549 case 0x3c: mnem = "sra"; break;
550 case 0x52: mnem = "mskwh"; break;
551 case 0x57: mnem = "inswh"; break;
552 case 0x5a: mnem = "extwh"; break;
553 case 0x62: mnem = "msklh"; break;
554 case 0x67: mnem = "inslh"; break;
555 case 0x6a: mnem = "extlh"; break;
556 case 0x72: mnem = "mskqh"; break;
557 case 0x77: mnem = "insqh"; break;
558 case 0x7a: mnem = "extqh"; break;
559 default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n",
560 opcode, func);
561 }
562 if (mnem == NULL)
563 break;
564 if (func & 0x80)
565 debug("%s\t%s,0x%x,%s\n", mnem,
566 alpha_regname[ra], (rb << 3) + (func >> 8),
567 alpha_regname[rc]);
568 else
569 debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra],
570 alpha_regname[rb], alpha_regname[rc]);
571 break;
572 case 0x13:
573 switch (func & 0x7f) {
574 case 0x00: mnem = "mull"; break;
575 case 0x20: mnem = "mulq"; break;
576 case 0x30: mnem = "umulh"; break;
577 case 0x40: mnem = "mull/v"; break;
578 case 0x60: mnem = "mulq/v"; break;
579 default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n",
580 opcode, func);
581 }
582 if (mnem == NULL)
583 break;
584 if (func & 0x80)
585 debug("%s\t%s,0x%x,%s\n", mnem,
586 alpha_regname[ra], (rb << 3) + (func >> 8),
587 alpha_regname[rc]);
588 else
589 debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra],
590 alpha_regname[rb], alpha_regname[rc]);
591 break;
592 case 0x16:
593 switch (func & 0x7ff) {
594 case 0x02f: mnem = "cvttq/c"; rbrc = 1; break;
595 case 0x080: mnem = "adds"; break;
596 case 0x081: mnem = "subs"; break;
597 case 0x082: mnem = "muls"; break;
598 case 0x083: mnem = "XXXx083"; break;
599 case 0x0a0: mnem = "addt"; break;
600 case 0x0a1: mnem = "subt"; break;
601 case 0x0a2: mnem = "mult"; break;
602 case 0x0a3: mnem = "divt"; break;
603 case 0x0a5: mnem = "cmpteq"; break;
604 case 0x0a6: mnem = "cmptlt"; break;
605 case 0x0a7: mnem = "cmptle"; break;
606 case 0x0be: mnem = "cvtqt"; rbrc = 1; break;
607 default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n",
608 opcode, func);
609 }
610 if (mnem == NULL)
611 break;
612 if (rbrc)
613 debug("%s\tf%i,f%i\n", mnem, rb, rc);
614 else
615 debug("%s\tf%i,f%i,f%i\n", mnem, ra, rb, rc);
616 break;
617 case 0x17:
618 switch (func & 0x7ff) {
619 case 0x020: mnem = "fabs"; rbrc = 1; break;
620 case 0x021: mnem = "fneg"; rbrc = 1; break;
621 default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n",
622 opcode, func);
623 }
624 if (mnem == NULL)
625 break;
626 if ((func & 0x7ff) == 0x020 && ra == 31 && rb == 31)
627 debug("fclr\tf%i\n", rc);
628 else if (rbrc)
629 debug("%s\tf%i,f%i\n", mnem, rb, rc);
630 else
631 debug("%s\tf%i,f%i,f%i\n", mnem, ra, rb, rc);
632 break;
633 case 0x18:
634 switch (iw & 0xffff) {
635 case 0x0000: mnem = "trapb"; break;
636 case 0x0400: mnem = "excb"; break;
637 case 0x4000: mnem = "mb"; break;
638 case 0x4400: mnem = "wmb"; break;
639 case 0x8000: mnem = "fetch"; indir = 1; break;
640 case 0xa000: mnem = "fetch_m"; indir = 1; break;
641 case 0xc000: mnem = "rpcc"; break;
642 case 0xe000: mnem = "rc"; break;
643 case 0xe800: mnem = "ecb"; indir = 1; break;
644 case 0xf000: mnem = "rs"; break;
645 case 0xf800: mnem = "wh64"; indir = 1; break;
646 default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n",
647 opcode, func);
648 }
649 if (mnem == NULL)
650 break;
651 debug("%s", mnem);
652 if ((iw & 0xffff) >= 0x8000) {
653 debug("\t");
654 if (indir)
655 debug("(%s)", alpha_regname[rb]);
656 else
657 debug("%s", alpha_regname[ra]);
658 }
659 debug("\n");
660 break;
661 case 0x1a:
662 tmp = iw & 0x3fff;
663 if (tmp & 0x2000)
664 tmp |= 0xffffffffffffc000ULL;
665 tmp <<= 2;
666 tmp += dumpaddr + sizeof(uint32_t);
667 switch ((iw >> 14) & 3) {
668 case 0:
669 case 1: if (((iw >> 14) & 3) == 0)
670 debug("jmp");
671 else
672 debug("jsr");
673 debug("\t%s,", alpha_regname[ra]);
674 debug("(%s),", alpha_regname[rb]);
675 debug("0x%"PRIx64, (uint64_t) tmp);
676 symbol = get_symbol_name(&cpu->machine->symbol_context,
677 tmp, &offset);
678 if (symbol != NULL)
679 debug("\t<%s>", symbol);
680 break;
681 case 2: debug("ret");
682 break;
683 default:fatal("unimpl JSR!");
684 }
685 debug("\n");
686 break;
687 case 0x30:
688 case 0x34:
689 tmp = iw & 0x1fffff;
690 if (tmp & 0x100000)
691 tmp |= 0xffffffffffe00000ULL;
692 tmp <<= 2;
693 tmp += dumpaddr + sizeof(uint32_t);
694 debug("%s\t", opcode==0x30? "br" : "bsr");
695 if (ra != ALPHA_ZERO)
696 debug("%s,", alpha_regname[ra]);
697 debug("0x%"PRIx64, (uint64_t) tmp);
698 symbol = get_symbol_name(&cpu->machine->symbol_context,
699 tmp, &offset);
700 if (symbol != NULL)
701 debug("\t<%s>", symbol);
702 debug("\n");
703 break;
704 case 0x31:
705 case 0x35:
706 case 0x38:
707 case 0x39:
708 case 0x3a:
709 case 0x3b:
710 case 0x3c:
711 case 0x3d:
712 case 0x3e:
713 case 0x3f:
714 floating = 0;
715 switch (opcode) {
716 case 0x31: mnem = "fbeq"; floating = 1; break;
717 case 0x35: mnem = "fbne"; floating = 1; break;
718 case 0x38: mnem = "blbc"; break;
719 case 0x39: mnem = "beq"; break;
720 case 0x3a: mnem = "blt"; break;
721 case 0x3b: mnem = "ble"; break;
722 case 0x3c: mnem = "blbs"; break;
723 case 0x3d: mnem = "bne"; break;
724 case 0x3e: mnem = "bge"; break;
725 case 0x3f: mnem = "bgt"; break;
726 }
727 tmp = iw & 0x1fffff;
728 if (tmp & 0x100000)
729 tmp |= 0xffffffffffe00000ULL;
730 tmp <<= 2;
731 tmp += dumpaddr + sizeof(uint32_t);
732 debug("%s\t", mnem);
733 if (floating)
734 debug("f%i,", ra);
735 else
736 debug("%s,", alpha_regname[ra]);
737 debug("0x%"PRIx64, (uint64_t) tmp);
738 symbol = get_symbol_name(&cpu->machine->symbol_context,
739 tmp, &offset);
740 if (symbol != NULL)
741 debug("\t<%s>", symbol);
742 debug("\n");
743 break;
744 default:debug("UNIMPLEMENTED opcode 0x%x\n", opcode);
745 }
746
747 return sizeof(uint32_t);
748 }
749
750
751 #define MEMORY_RW alpha_userland_memory_rw
752 #define MEM_ALPHA
753 #define MEM_USERLAND
754 #include "../memory_rw.c"
755 #undef MEM_USERLAND
756 #undef MEM_ALPHA
757 #undef MEMORY_RW
758
759
760 #include "tmp_alpha_tail.c"
761

  ViewVC Help
Powered by ViewVC 1.1.26