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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (13 years, 3 months ago) by dpavlin
File MIME type: text/plain
File size: 26300 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


1 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2005-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 28 * $Id: cpu_sparc_instr.c,v 1.21 2006/07/02 11:01:19 debug Exp $
29 dpavlin 14 *
30     * SPARC instructions.
31     *
32     * Individual functions should keep track of cpu->n_translated_instrs.
33     * (If no instruction was executed, then it should be decreased. If, say, 4
34     * instructions were combined into one function and executed, then it should
35     * be increased by 3.)
36     */
37    
38    
39     /*
40 dpavlin 28 * invalid: For catching bugs.
41     */
42     X(invalid)
43     {
44     fatal("FATAL ERROR: An internal error occured in the SPARC"
45     " dyntrans code. Please contact the author with detailed"
46     " repro steps on how to trigger this bug.\n");
47     exit(1);
48     }
49    
50    
51     /*
52 dpavlin 14 * nop: Do nothing.
53     */
54     X(nop)
55     {
56     }
57    
58    
59     /*****************************************************************************/
60    
61    
62 dpavlin 24 /*
63     * call
64     *
65     * arg[0] = int32_t displacement compared to the current instruction
66     * arg[1] = int32_t displacement of current instruction compared to
67     * start of the page
68     */
69     X(call)
70     {
71     MODE_uint_t old_pc = cpu->pc;
72     old_pc &= ~((SPARC_IC_ENTRIES_PER_PAGE - 1)
73     << SPARC_INSTR_ALIGNMENT_SHIFT);
74     old_pc += (int32_t)ic->arg[1];
75     cpu->cd.sparc.r[SPARC_REG_O7] = old_pc;
76     cpu->delay_slot = TO_BE_DELAYED;
77     ic[1].f(cpu, ic+1);
78     cpu->n_translated_instrs ++;
79     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
80     /* Note: Must be non-delayed when jumping to the new pc: */
81     cpu->delay_slot = NOT_DELAYED;
82     cpu->pc = old_pc + (int32_t)ic->arg[0];
83     quick_pc_to_pointers(cpu);
84     } else
85     cpu->delay_slot = NOT_DELAYED;
86     }
87     X(call_trace)
88     {
89     MODE_uint_t old_pc = cpu->pc;
90     old_pc &= ~((SPARC_IC_ENTRIES_PER_PAGE - 1)
91     << SPARC_INSTR_ALIGNMENT_SHIFT);
92     old_pc += (int32_t)ic->arg[1];
93     cpu->cd.sparc.r[SPARC_REG_O7] = old_pc;
94     cpu->delay_slot = TO_BE_DELAYED;
95     ic[1].f(cpu, ic+1);
96     cpu->n_translated_instrs ++;
97     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
98     /* Note: Must be non-delayed when jumping to the new pc: */
99     cpu->delay_slot = NOT_DELAYED;
100     cpu->pc = old_pc + (int32_t)ic->arg[0];
101     cpu_functioncall_trace(cpu, cpu->pc);
102     quick_pc_to_pointers(cpu);
103     } else
104     cpu->delay_slot = NOT_DELAYED;
105     }
106    
107    
108     /*
109     * ba
110     *
111     * arg[0] = int32_t displacement compared to the start of the current page
112     */
113     X(ba)
114     {
115     MODE_uint_t old_pc = cpu->pc;
116     cpu->delay_slot = TO_BE_DELAYED;
117     ic[1].f(cpu, ic+1);
118     cpu->n_translated_instrs ++;
119     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
120     /* Note: Must be non-delayed when jumping to the new pc: */
121     cpu->delay_slot = NOT_DELAYED;
122     old_pc &= ~((SPARC_IC_ENTRIES_PER_PAGE - 1)
123     << SPARC_INSTR_ALIGNMENT_SHIFT);
124     cpu->pc = old_pc + (int32_t)ic->arg[0];
125     quick_pc_to_pointers(cpu);
126     } else
127     cpu->delay_slot = NOT_DELAYED;
128     }
129    
130    
131     /*
132     * Jump and link
133     *
134     * arg[0] = ptr to rs1
135     * arg[1] = ptr to rs2 or an immediate value (int32_t)
136     * arg[2] = ptr to rd
137     */
138     X(jmpl_imm)
139     {
140     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
141     / sizeof(struct sparc_instr_call);
142     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
143     << SPARC_INSTR_ALIGNMENT_SHIFT);
144     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
145     reg(ic->arg[2]) = cpu->pc;
146    
147     cpu->delay_slot = TO_BE_DELAYED;
148     ic[1].f(cpu, ic+1);
149     cpu->n_translated_instrs ++;
150    
151     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
152     /* Note: Must be non-delayed when jumping to the new pc: */
153     cpu->delay_slot = NOT_DELAYED;
154     cpu->pc = reg(ic->arg[0]) + (int32_t)ic->arg[1];
155     quick_pc_to_pointers(cpu);
156     } else
157     cpu->delay_slot = NOT_DELAYED;
158     }
159     X(jmpl_imm_no_rd)
160     {
161     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
162     / sizeof(struct sparc_instr_call);
163     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
164     << SPARC_INSTR_ALIGNMENT_SHIFT);
165     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
166    
167     cpu->delay_slot = TO_BE_DELAYED;
168     ic[1].f(cpu, ic+1);
169     cpu->n_translated_instrs ++;
170    
171     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
172     /* Note: Must be non-delayed when jumping to the new pc: */
173     cpu->delay_slot = NOT_DELAYED;
174     cpu->pc = reg(ic->arg[0]) + (int32_t)ic->arg[1];
175     quick_pc_to_pointers(cpu);
176     } else
177     cpu->delay_slot = NOT_DELAYED;
178     }
179     X(jmpl_reg)
180     {
181     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
182     / sizeof(struct sparc_instr_call);
183     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
184     << SPARC_INSTR_ALIGNMENT_SHIFT);
185     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
186     reg(ic->arg[2]) = cpu->pc;
187    
188     cpu->delay_slot = TO_BE_DELAYED;
189     ic[1].f(cpu, ic+1);
190     cpu->n_translated_instrs ++;
191    
192     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
193     /* Note: Must be non-delayed when jumping to the new pc: */
194     cpu->delay_slot = NOT_DELAYED;
195     cpu->pc = reg(ic->arg[0]) + reg(ic->arg[1]);
196     quick_pc_to_pointers(cpu);
197     } else
198     cpu->delay_slot = NOT_DELAYED;
199     }
200     X(jmpl_reg_no_rd)
201     {
202     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
203     / sizeof(struct sparc_instr_call);
204     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
205     << SPARC_INSTR_ALIGNMENT_SHIFT);
206     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
207    
208     cpu->delay_slot = TO_BE_DELAYED;
209     ic[1].f(cpu, ic+1);
210     cpu->n_translated_instrs ++;
211    
212     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
213     /* Note: Must be non-delayed when jumping to the new pc: */
214     cpu->delay_slot = NOT_DELAYED;
215     cpu->pc = reg(ic->arg[0]) + reg(ic->arg[1]);
216     quick_pc_to_pointers(cpu);
217     } else
218     cpu->delay_slot = NOT_DELAYED;
219     }
220    
221    
222     X(jmpl_imm_trace)
223     {
224     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
225     / sizeof(struct sparc_instr_call);
226     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
227     << SPARC_INSTR_ALIGNMENT_SHIFT);
228     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
229     reg(ic->arg[2]) = cpu->pc;
230    
231     cpu->delay_slot = TO_BE_DELAYED;
232     ic[1].f(cpu, ic+1);
233     cpu->n_translated_instrs ++;
234    
235     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
236     /* Note: Must be non-delayed when jumping to the new pc: */
237     cpu->delay_slot = NOT_DELAYED;
238     cpu->pc = reg(ic->arg[0]) + (int32_t)ic->arg[1];
239     cpu_functioncall_trace(cpu, cpu->pc);
240     quick_pc_to_pointers(cpu);
241     } else
242     cpu->delay_slot = NOT_DELAYED;
243     }
244     X(jmpl_reg_trace)
245     {
246     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
247     / sizeof(struct sparc_instr_call);
248     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
249     << SPARC_INSTR_ALIGNMENT_SHIFT);
250     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
251     reg(ic->arg[2]) = cpu->pc;
252    
253     cpu->delay_slot = TO_BE_DELAYED;
254     ic[1].f(cpu, ic+1);
255     cpu->n_translated_instrs ++;
256    
257     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
258     /* Note: Must be non-delayed when jumping to the new pc: */
259     cpu->delay_slot = NOT_DELAYED;
260     cpu->pc = reg(ic->arg[0]) + reg(ic->arg[1]);
261     cpu_functioncall_trace(cpu, cpu->pc);
262     quick_pc_to_pointers(cpu);
263     } else
264     cpu->delay_slot = NOT_DELAYED;
265     }
266     X(retl_trace)
267     {
268     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
269     / sizeof(struct sparc_instr_call);
270     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
271     << SPARC_INSTR_ALIGNMENT_SHIFT);
272     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
273    
274     cpu->delay_slot = TO_BE_DELAYED;
275     ic[1].f(cpu, ic+1);
276     cpu->n_translated_instrs ++;
277    
278     if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
279     /* Note: Must be non-delayed when jumping to the new pc: */
280     cpu->delay_slot = NOT_DELAYED;
281     cpu->pc = reg(ic->arg[0]) + (int32_t)ic->arg[1];
282     quick_pc_to_pointers(cpu);
283     cpu_functioncall_trace_return(cpu);
284     } else
285     cpu->delay_slot = NOT_DELAYED;
286     }
287    
288    
289     /*
290     * set: Set a register to a value (e.g. sethi).
291     *
292     * arg[0] = ptr to rd
293     * arg[1] = value (uint32_t)
294     */
295     X(set)
296     {
297     reg(ic->arg[0]) = (uint32_t)ic->arg[1];
298     }
299    
300    
301     /*
302     * Computational/arithmetic instructions:
303     *
304     * arg[0] = ptr to rs1
305     * arg[1] = ptr to rs2 or an immediate value (int32_t)
306     * arg[2] = ptr to rd
307     */
308     X(add) { reg(ic->arg[2]) = reg(ic->arg[0]) + reg(ic->arg[1]); }
309     X(add_imm) { reg(ic->arg[2]) = reg(ic->arg[0]) + (int32_t)ic->arg[1]; }
310     X(and) { reg(ic->arg[2]) = reg(ic->arg[0]) & reg(ic->arg[1]); }
311     X(and_imm) { reg(ic->arg[2]) = reg(ic->arg[0]) & (int32_t)ic->arg[1]; }
312     X(or) { reg(ic->arg[2]) = reg(ic->arg[0]) | reg(ic->arg[1]); }
313     X(or_imm) { reg(ic->arg[2]) = reg(ic->arg[0]) | (int32_t)ic->arg[1]; }
314     X(xor) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ reg(ic->arg[1]); }
315     X(xor_imm) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ (int32_t)ic->arg[1]; }
316     X(sub) { reg(ic->arg[2]) = reg(ic->arg[0]) - reg(ic->arg[1]); }
317     X(sub_imm) { reg(ic->arg[2]) = reg(ic->arg[0]) - (int32_t)ic->arg[1]; }
318    
319     X(sll) { reg(ic->arg[2]) = (uint32_t)reg(ic->arg[0]) <<
320     (reg(ic->arg[1]) & 31); }
321     X(sllx) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) <<
322     (reg(ic->arg[1]) & 63); }
323     X(sll_imm) { reg(ic->arg[2]) = (uint32_t)reg(ic->arg[0]) << ic->arg[1]; }
324     X(sllx_imm) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) << ic->arg[1]; }
325    
326     X(srl) { reg(ic->arg[2]) = (uint32_t)reg(ic->arg[0]) >>
327     (reg(ic->arg[1]) & 31); }
328     X(srlx) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) >>
329     (reg(ic->arg[1]) & 63); }
330     X(srl_imm) { reg(ic->arg[2]) = (uint32_t)reg(ic->arg[0]) >> ic->arg[1]; }
331     X(srlx_imm) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) >> ic->arg[1]; }
332    
333     X(sra) { reg(ic->arg[2]) = (int32_t)reg(ic->arg[0]) >>
334     (reg(ic->arg[1]) & 31); }
335     X(srax) { reg(ic->arg[2]) = (int64_t)reg(ic->arg[0]) >>
336     (reg(ic->arg[1]) & 63); }
337     X(sra_imm) { reg(ic->arg[2]) = (int32_t)reg(ic->arg[0]) >> ic->arg[1]; }
338     X(srax_imm) { reg(ic->arg[2]) = (int64_t)reg(ic->arg[0]) >> ic->arg[1]; }
339    
340    
341     /*
342 dpavlin 28 * Save:
343     *
344     * arg[0] = ptr to rs1
345     * arg[1] = ptr to rs2 or an immediate value (int32_t)
346     * arg[2] = ptr to rd (_after_ the register window change)
347     */
348     X(save_v9_imm)
349     {
350     MODE_uint_t rs = reg(ic->arg[0]) + (int32_t)ic->arg[1];
351     int cwp = cpu->cd.sparc.cwp;
352    
353     if (cpu->cd.sparc.cansave == 0) {
354     fatal("save_v9_imm: spill trap. TODO\n");
355     exit(1);
356     }
357    
358     if (cpu->cd.sparc.cleanwin - cpu->cd.sparc.canrestore == 0) {
359     fatal("save_v9_imm: clean_window trap. TODO\n");
360     exit(1);
361     }
362    
363     /* Save away old in registers: */
364     memcpy(&cpu->cd.sparc.r_inout[cwp][0], &cpu->cd.sparc.r[SPARC_REG_I0],
365     sizeof(cpu->cd.sparc.r[SPARC_REG_I0]) * N_SPARC_INOUT_REG);
366    
367     /* Save away old local registers: */
368     memcpy(&cpu->cd.sparc.r_local[cwp][0], &cpu->cd.sparc.r[SPARC_REG_L0],
369     sizeof(cpu->cd.sparc.r[SPARC_REG_L0]) * N_SPARC_INOUT_REG);
370    
371     cwp = cpu->cd.sparc.cwp = (cwp + 1) % cpu->cd.sparc.cpu_type.nwindows;
372     cpu->cd.sparc.cansave --;
373     cpu->cd.sparc.canrestore ++; /* TODO: modulo here too? */
374    
375     /* The out registers become the new in registers: */
376     memcpy(&cpu->cd.sparc.r[SPARC_REG_I0], &cpu->cd.sparc.r[SPARC_REG_O0],
377     sizeof(cpu->cd.sparc.r[SPARC_REG_O0]) * N_SPARC_INOUT_REG);
378    
379     /* Read new local registers: */
380     memcpy(&cpu->cd.sparc.r[SPARC_REG_L0], &cpu->cd.sparc.r_local[cwp][0],
381     sizeof(cpu->cd.sparc.r[SPARC_REG_L0]) * N_SPARC_INOUT_REG);
382    
383     reg(ic->arg[2]) = rs;
384     }
385    
386    
387     /*
388 dpavlin 24 * Subtract with ccr update:
389     *
390     * arg[0] = ptr to rs1
391     * arg[1] = ptr to rs2 or an immediate value (int32_t)
392     * arg[2] = ptr to rd
393     */
394     int32_t sparc_subcc32(struct cpu *cpu, int32_t rs1, int32_t rs2);
395     #ifdef MODE32
396     int32_t sparc_subcc32(struct cpu *cpu, int32_t rs1, int32_t rs2)
397     #else
398     int64_t sparc_subcc64(struct cpu *cpu, int64_t rs1, int64_t rs2)
399     #endif
400     {
401     int cc = 0, sign1 = 0, sign2 = 0, signd = 0, mask = SPARC_CCR_ICC_MASK;
402     MODE_int_t rd = rs1 - rs2;
403     if (rd == 0)
404     cc = SPARC_CCR_Z;
405     else if (rd < 0)
406     cc = SPARC_CCR_N, signd = 1;
407     if (rs1 < 0)
408     sign1 = 1;
409     if (rs2 < 0)
410     sign2 = 1;
411     if (sign1 != sign2 && sign1 != signd)
412     cc |= SPARC_CCR_V;
413     /* TODO: SPARC_CCR_C */
414     #ifndef MODE32
415     mask <<= SPARC_CCR_XCC_SHIFT;
416     cc <<= SPARC_CCR_XCC_SHIFT;
417     #endif
418     cpu->cd.sparc.ccr &= ~mask;
419     cpu->cd.sparc.ccr |= cc;
420     return rd;
421     }
422     X(subcc)
423     {
424     /* Like sub, but updates the ccr, and does both 32-bit and
425     64-bit comparison at the same time. */
426     MODE_int_t rs1 = reg(ic->arg[0]), rs2 = reg(ic->arg[1]), rd;
427     rd = sparc_subcc32(cpu, rs1, rs2);
428     #ifndef MODE32
429     rd = sparc_subcc64(cpu, rs1, rs2);
430     #endif
431     reg(ic->arg[2]) = rd;
432     }
433     X(subcc_imm)
434     {
435     MODE_int_t rs1 = reg(ic->arg[0]), rs2 = (int32_t)ic->arg[1], rd;
436     rd = sparc_subcc32(cpu, rs1, rs2);
437     #ifndef MODE32
438     rd = sparc_subcc64(cpu, rs1, rs2);
439     #endif
440     reg(ic->arg[2]) = rd;
441     }
442    
443    
444 dpavlin 28 #include "tmp_sparc_loadstore.c"
445    
446    
447 dpavlin 24 /*
448     * rd: Read special register:
449     *
450     * arg[2] = ptr to rd
451     */
452     X(rd_psr)
453     {
454     reg(ic->arg[2]) = cpu->cd.sparc.psr;
455     }
456    
457    
458     /*
459     * wrpr: Write to privileged register
460     *
461     * arg[0] = ptr to rs1
462     * arg[1] = ptr to rs2 or an immediate value (int32_t)
463     */
464     X(wrpr_tick)
465     {
466     cpu->cd.sparc.tick = (uint32_t) (reg(ic->arg[0]) ^ reg(ic->arg[1]));
467     }
468     X(wrpr_tick_imm)
469     {
470     cpu->cd.sparc.tick = (uint32_t) (reg(ic->arg[0]) ^ (int32_t)ic->arg[1]);
471     }
472     X(wrpr_pil)
473     {
474     cpu->cd.sparc.pil = (reg(ic->arg[0]) ^ reg(ic->arg[1]))
475     & SPARC_PIL_MASK;
476     }
477     X(wrpr_pil_imm)
478     {
479     cpu->cd.sparc.pil = (reg(ic->arg[0]) ^ (int32_t)ic->arg[1])
480     & SPARC_PIL_MASK;
481     }
482     X(wrpr_pstate)
483     {
484     sparc_update_pstate(cpu, reg(ic->arg[0]) ^ reg(ic->arg[1]));
485     }
486     X(wrpr_pstate_imm)
487     {
488     sparc_update_pstate(cpu, reg(ic->arg[0]) ^ (int32_t)ic->arg[1]);
489     }
490    
491    
492     /*****************************************************************************/
493    
494    
495 dpavlin 14 X(end_of_page)
496     {
497     /* Update the PC: (offset 0, but on the next page) */
498     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1) <<
499     SPARC_INSTR_ALIGNMENT_SHIFT);
500     cpu->pc += (SPARC_IC_ENTRIES_PER_PAGE <<
501     SPARC_INSTR_ALIGNMENT_SHIFT);
502    
503     /* Find the new physical page and update the translation pointers: */
504 dpavlin 24 quick_pc_to_pointers(cpu);
505 dpavlin 14
506     /* end_of_page doesn't count as an executed instruction: */
507     cpu->n_translated_instrs --;
508     }
509    
510    
511 dpavlin 24 X(end_of_page2)
512     {
513     /* Synchronize PC on the _second_ instruction on the next page: */
514     int low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
515     / sizeof(struct sparc_instr_call);
516     cpu->pc &= ~((SPARC_IC_ENTRIES_PER_PAGE-1)
517     << SPARC_INSTR_ALIGNMENT_SHIFT);
518     cpu->pc += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
519    
520     /* This doesn't count as an executed instruction. */
521     cpu->n_translated_instrs --;
522    
523     quick_pc_to_pointers(cpu);
524    
525     if (cpu->delay_slot == NOT_DELAYED)
526     return;
527    
528     fatal("end_of_page2: fatal error, we're in a delay slot\n");
529     exit(1);
530     }
531    
532    
533 dpavlin 14 /*****************************************************************************/
534    
535    
536     /*
537     * sparc_instr_to_be_translated():
538     *
539 dpavlin 24 * Translate an instruction word into a sparc_instr_call. ic is filled in with
540 dpavlin 14 * valid data for the translated instruction, or a "nothing" instruction if
541     * there was a translation failure. The newly translated instruction is then
542     * executed.
543     */
544     X(to_be_translated)
545     {
546 dpavlin 24 MODE_uint_t addr;
547 dpavlin 28 int low_pc, in_crosspage_delayslot = 0;
548 dpavlin 14 uint32_t iword;
549     unsigned char *page;
550     unsigned char ib[4];
551 dpavlin 24 int main_opcode, op2, rd, rs1, rs2, btype, asi, cc, p, use_imm, x64 = 0;
552 dpavlin 28 int store, signedness, size;
553 dpavlin 24 int32_t tmpi32, siconst;
554 dpavlin 20 /* void (*samepage_function)(struct cpu *, struct sparc_instr_call *);*/
555 dpavlin 14
556     /* Figure out the (virtual) address of the instruction: */
557     low_pc = ((size_t)ic - (size_t)cpu->cd.sparc.cur_ic_page)
558     / sizeof(struct sparc_instr_call);
559 dpavlin 24
560     /* Special case for branch with delayslot on the next page: */
561     if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) {
562     /* fatal("[ delay-slot translation across page "
563     "boundary ]\n"); */
564     in_crosspage_delayslot = 1;
565     }
566    
567 dpavlin 14 addr = cpu->pc & ~((SPARC_IC_ENTRIES_PER_PAGE-1)
568     << SPARC_INSTR_ALIGNMENT_SHIFT);
569     addr += (low_pc << SPARC_INSTR_ALIGNMENT_SHIFT);
570     cpu->pc = addr;
571     addr &= ~((1 << SPARC_INSTR_ALIGNMENT_SHIFT) - 1);
572    
573     /* Read the instruction word from memory: */
574 dpavlin 24 #ifdef MODE32
575 dpavlin 14 page = cpu->cd.sparc.host_load[addr >> 12];
576 dpavlin 24 #else
577     {
578     const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
579     const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
580     const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
581     uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1;
582     uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
583     uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N-
584     DYNTRANS_L3N)) & mask3;
585     struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.sparc.l1_64[x1];
586     struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2];
587     page = l3->host_load[x3];
588     }
589     #endif
590 dpavlin 14
591     if (page != NULL) {
592     /* fatal("TRANSLATION HIT!\n"); */
593 dpavlin 24 memcpy(ib, page + (addr & 0xffc), sizeof(ib));
594 dpavlin 14 } else {
595     /* fatal("TRANSLATION MISS!\n"); */
596     if (!cpu->memory_rw(cpu, cpu->mem, addr, ib,
597     sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
598     fatal("to_be_translated(): "
599     "read failed: TODO\n");
600     goto bad;
601     }
602     }
603    
604 dpavlin 24 /* SPARC instruction words are always big-endian. Convert
605     to host order: */
606     iword = BE32_TO_HOST( *((uint32_t *)&ib[0]) );
607 dpavlin 14
608    
609     #define DYNTRANS_TO_BE_TRANSLATED_HEAD
610     #include "cpu_dyntrans.c"
611     #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
612    
613    
614     /*
615     * Translate the instruction:
616     */
617    
618 dpavlin 24 main_opcode = iword >> 30;
619     rd = (iword >> 25) & 31;
620     btype = rd & (N_SPARC_BRANCH_TYPES - 1);
621     rs1 = (iword >> 14) & 31;
622     use_imm = (iword >> 13) & 1;
623     asi = (iword >> 5) & 0xff;
624     rs2 = iword & 31;
625     siconst = (int16_t)((iword & 0x1fff) << 3) >> 3;
626     op2 = (main_opcode == 0)? ((iword >> 22) & 7) : ((iword >> 19) & 0x3f);
627     cc = (iword >> 20) & 3;
628     p = (iword >> 19) & 1;
629 dpavlin 14
630     switch (main_opcode) {
631    
632 dpavlin 24 case 0: switch (op2) {
633    
634     case 2: /* branch (32-bit integer comparison) */
635     tmpi32 = (iword << 10);
636     tmpi32 >>= 8;
637     ic->arg[0] = (int32_t)tmpi32 + (addr & 0xffc);
638     /* rd contains the annul bit concatenated with 4 bits
639     of condition code: */
640     /* TODO: samepage */
641     switch (rd) {
642     case 0x08:/* ba */
643     ic->f = instr(ba);
644     break;
645     default:goto bad;
646     }
647     break;
648    
649     case 4: /* sethi */
650     ic->arg[0] = (size_t)&cpu->cd.sparc.r[rd];
651     ic->arg[1] = (iword & 0x3fffff) << 10;
652     ic->f = instr(set);
653     if (rd == SPARC_ZEROREG)
654     ic->f = instr(nop);
655     break;
656    
657     default:fatal("TODO: unimplemented op2=%i for main "
658     "opcode %i\n", op2, main_opcode);
659     goto bad;
660     }
661     break;
662    
663     case 1: /* call and link */
664     tmpi32 = (iword << 2);
665     ic->arg[0] = (int32_t)tmpi32;
666     ic->arg[1] = addr & 0xffc;
667     if (cpu->machine->show_trace_tree)
668     ic->f = instr(call_trace);
669     else
670     ic->f = instr(call);
671     /* TODO: samepage */
672     break;
673    
674     case 2: switch (op2) {
675    
676     case 0: /* add */
677     case 1: /* and */
678     case 2: /* or */
679     case 3: /* xor */
680     case 4: /* sub */
681     case 20:/* subcc (cmp) */
682     case 37:/* sll */
683     case 38:/* srl */
684     case 39:/* sra */
685 dpavlin 28 case 60:/* save */
686 dpavlin 24 ic->arg[0] = (size_t)&cpu->cd.sparc.r[rs1];
687     ic->f = NULL;
688     if (use_imm) {
689     ic->arg[1] = siconst;
690     switch (op2) {
691     case 0: ic->f = instr(add_imm); break;
692     case 1: ic->f = instr(and_imm); break;
693     case 2: ic->f = instr(or_imm); break;
694     case 3: ic->f = instr(xor_imm); break;
695     case 4: ic->f = instr(sub_imm); break;
696     case 20:ic->f = instr(subcc_imm); break;
697     case 37:if (siconst & 0x1000) {
698     ic->f = instr(sllx_imm);
699     ic->arg[1] &= 63;
700     x64 = 1;
701     } else {
702     ic->f = instr(sll_imm);
703     ic->arg[1] &= 31;
704     }
705     break;
706     case 38:if (siconst & 0x1000) {
707     ic->f = instr(srlx_imm);
708     ic->arg[1] &= 63;
709     x64 = 1;
710     } else {
711     ic->f = instr(srl_imm);
712     ic->arg[1] &= 31;
713     }
714     break;
715     case 39:if (siconst & 0x1000) {
716     ic->f = instr(srax_imm);
717     ic->arg[1] &= 63;
718     x64 = 1;
719     } else {
720     ic->f = instr(sra_imm);
721     ic->arg[1] &= 31;
722     }
723     break;
724 dpavlin 28 case 60:switch (cpu->cd.sparc.cpu_type.v) {
725     case 9: ic->f = instr(save_v9_imm);
726     break;
727     default:fatal("only for v9 so far\n");
728     goto bad;
729     }
730 dpavlin 24 }
731     } else {
732     ic->arg[1] = (size_t)&cpu->cd.sparc.r[rs2];
733     switch (op2) {
734     case 0: ic->f = instr(add); break;
735     case 1: ic->f = instr(and); break;
736     case 2: ic->f = instr(or); break;
737     case 3: ic->f = instr(xor); break;
738     case 4: ic->f = instr(sub); break;
739     case 20:ic->f = instr(subcc); break;
740     case 37:if (siconst & 0x1000) {
741     ic->f = instr(sllx);
742     x64 = 1;
743     } else
744     ic->f = instr(sll);
745     break;
746     case 38:if (siconst & 0x1000) {
747     ic->f = instr(srlx);
748     x64 = 1;
749     } else
750     ic->f = instr(srl);
751     break;
752     case 39:if (siconst & 0x1000) {
753     ic->f = instr(srax);
754     x64 = 1;
755     } else
756     ic->f = instr(sra);
757     break;
758     }
759     }
760     if (ic->f == NULL) {
761     fatal("TODO: Unimplemented instruction "
762     "(possibly missed use_imm impl.)\n");
763     goto bad;
764     }
765     ic->arg[2] = (size_t)&cpu->cd.sparc.r[rd];
766     if (rd == SPARC_ZEROREG) {
767 dpavlin 28 /*
768     * Some opcodes should write to the scratch
769     * register instead of becoming NOPs, when
770     * rd is the zero register.
771     */
772 dpavlin 24 switch (op2) {
773     case 20:/* subcc */
774 dpavlin 28 case 60:/* save */
775 dpavlin 24 ic->arg[2] = (size_t)
776     &cpu->cd.sparc.scratch;
777     break;
778     default:ic->f = instr(nop);
779     }
780     }
781     break;
782    
783     case 41:/* rd %psr,%gpr on pre-sparcv9 */
784     if (cpu->is_32bit) {
785     ic->f = instr(rd_psr);
786     ic->arg[2] = (size_t)&cpu->cd.sparc.r[rd];
787     if (rd == SPARC_ZEROREG)
788     ic->f = instr(nop);
789     } else {
790     fatal("opcode 2,41 not yet implemented"
791     " for 64-bit cpus\n");
792     goto bad;
793     }
794     break;
795    
796     case 48:/* wr (Note: works as xor) */
797     ic->arg[0] = (size_t)&cpu->cd.sparc.r[rs1];
798     if (use_imm) {
799     ic->arg[1] = siconst;
800     ic->f = instr(xor_imm);
801     } else {
802     ic->arg[1] = (size_t)&cpu->cd.sparc.r[rs2];
803     ic->f = instr(xor);
804     }
805     ic->arg[2] = (size_t) NULL;
806     switch (rd) {
807     case 0: ic->arg[2] = (size_t)&cpu->cd.sparc.y;
808     break;
809     case 6: ic->arg[2] = (size_t)&cpu->cd.sparc.fprs;
810     break;
811     case 0x17:
812     ic->arg[2] = (size_t)&cpu->cd.sparc.tick_cmpr;
813     break;
814     }
815     if (ic->arg[2] == (size_t)NULL) {
816     fatal("TODO: Unimplemented wr instruction, "
817     "rd = 0x%02x\n", rd);
818     goto bad;
819     }
820     break;
821    
822     case 50:/* wrpr (Note: works as xor) */
823     ic->arg[0] = (size_t)&cpu->cd.sparc.r[rs1];
824     ic->f = NULL;
825     if (use_imm) {
826     ic->arg[1] = siconst;
827     switch (rd) {
828     case 4: ic->f = instr(wrpr_tick_imm); break;
829     case 6: ic->f = instr(wrpr_pstate_imm); break;
830     case 8: ic->f = instr(wrpr_pil_imm); break;
831     }
832     } else {
833     ic->arg[1] = (size_t)&cpu->cd.sparc.r[rs2];
834     switch (rd) {
835     case 4: ic->f = instr(wrpr_tick); break;
836     case 6: ic->f = instr(wrpr_pstate); break;
837     case 8: ic->f = instr(wrpr_pil); break;
838     }
839     }
840     if (ic->f == NULL) {
841     fatal("TODO: Unimplemented wrpr instruction,"
842     " rd = 0x%02x\n", rd);
843     goto bad;
844     }
845     break;
846    
847     case 56:/* jump and link */
848     ic->arg[0] = (size_t)&cpu->cd.sparc.r[rs1];
849     ic->arg[2] = (size_t)&cpu->cd.sparc.r[rd];
850     if (rd == SPARC_ZEROREG)
851     ic->arg[2] = (size_t)&cpu->cd.sparc.scratch;
852    
853     if (use_imm) {
854     ic->arg[1] = siconst;
855     if (rd == SPARC_ZEROREG)
856     ic->f = instr(jmpl_imm_no_rd);
857     else
858     ic->f = instr(jmpl_imm);
859     } else {
860     ic->arg[1] = (size_t)&cpu->cd.sparc.r[rs2];
861     if (rd == SPARC_ZEROREG)
862     ic->f = instr(jmpl_reg_no_rd);
863     else
864     ic->f = instr(jmpl_reg);
865     }
866    
867     /* special trace case: */
868     if (cpu->machine->show_trace_tree) {
869     if (iword == 0x81c3e008)
870     ic->f = instr(retl_trace);
871     else {
872     if (use_imm)
873     ic->f = instr(jmpl_imm_trace);
874     else
875     ic->f = instr(jmpl_reg_trace);
876     }
877     }
878     break;
879    
880     default:fatal("TODO: unimplemented op2=%i for main "
881     "opcode %i\n", op2, main_opcode);
882     goto bad;
883     }
884     break;
885    
886 dpavlin 28 case 3: switch (op2) {
887    
888     case 0:/* lduw */
889     case 1:/* ldub */
890     case 2:/* lduh */
891     case 4:/* st(w) */
892     case 5:/* stb */
893     case 6:/* sth */
894     case 8:/* ldsw */
895     case 9:/* ldsb */
896     case 10:/* ldsh */
897     case 11:/* ldx */
898     case 14:/* stx */
899     store = 1; signedness = 0; size = 3;
900     switch (op2) {
901     case 0: /* lduw */ store=0; size=2; break;
902     case 1: /* ldub */ store=0; size=0; break;
903     case 2: /* lduh */ store=0; size=1; break;
904     case 4: /* st */ size = 2; break;
905     case 5: /* stb */ size = 0; break;
906     case 6: /* sth */ size = 1; break;
907     case 8: /* ldsw */ store=0; size=2; signedness=1;
908     break;
909     case 9: /* ldsb */ store=0; size=0; signedness=1;
910     break;
911     case 10: /* ldsh */ store=0; size=1; signedness=1;
912     break;
913     case 11: /* ldx */ store=0; break;
914     case 14: /* stx */ break;
915     }
916     ic->f =
917     #ifdef MODE32
918     sparc32_loadstore
919     #else
920     sparc_loadstore
921     #endif
922     [ use_imm*16 + store*8 + size*2 + signedness ];
923    
924     ic->arg[0] = (size_t)&cpu->cd.sparc.r[rd];
925     ic->arg[1] = (size_t)&cpu->cd.sparc.r[rs1];
926     if (use_imm)
927     ic->arg[2] = siconst;
928     else
929     ic->arg[2] = (size_t)&cpu->cd.sparc.r[rs2];
930    
931     if (!store && rd == SPARC_ZEROREG)
932     ic->arg[0] = (size_t)&cpu->cd.sparc.scratch;
933    
934     break;
935    
936     default:fatal("TODO: unimplemented op2=%i for main "
937     "opcode %i\n", op2, main_opcode);
938     goto bad;
939     }
940     break;
941    
942 dpavlin 14 }
943    
944    
945 dpavlin 24 if (x64 && cpu->is_32bit) {
946     fatal("TODO: 64-bit instr on 32-bit cpu\n");
947     goto bad;
948     }
949    
950    
951 dpavlin 14 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
952     #include "cpu_dyntrans.c"
953     #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
954     }
955    

  ViewVC Help
Powered by ViewVC 1.1.26