/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 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 /*
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_sparc_instr.c,v 1.21 2006/07/02 11:01:19 debug Exp $
29 *
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 * 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 * nop: Do nothing.
53 */
54 X(nop)
55 {
56 }
57
58
59 /*****************************************************************************/
60
61
62 /*
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 * 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 * 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 #include "tmp_sparc_loadstore.c"
445
446
447 /*
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 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 quick_pc_to_pointers(cpu);
505
506 /* end_of_page doesn't count as an executed instruction: */
507 cpu->n_translated_instrs --;
508 }
509
510
511 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 /*****************************************************************************/
534
535
536 /*
537 * sparc_instr_to_be_translated():
538 *
539 * Translate an instruction word into a sparc_instr_call. ic is filled in with
540 * 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 MODE_uint_t addr;
547 int low_pc, in_crosspage_delayslot = 0;
548 uint32_t iword;
549 unsigned char *page;
550 unsigned char ib[4];
551 int main_opcode, op2, rd, rs1, rs2, btype, asi, cc, p, use_imm, x64 = 0;
552 int store, signedness, size;
553 int32_t tmpi32, siconst;
554 /* void (*samepage_function)(struct cpu *, struct sparc_instr_call *);*/
555
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
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 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 #ifdef MODE32
575 page = cpu->cd.sparc.host_load[addr >> 12];
576 #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
591 if (page != NULL) {
592 /* fatal("TRANSLATION HIT!\n"); */
593 memcpy(ib, page + (addr & 0xffc), sizeof(ib));
594 } 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 /* SPARC instruction words are always big-endian. Convert
605 to host order: */
606 iword = BE32_TO_HOST( *((uint32_t *)&ib[0]) );
607
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 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
630 switch (main_opcode) {
631
632 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 case 60:/* save */
686 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 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 }
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 /*
768 * Some opcodes should write to the scratch
769 * register instead of becoming NOPs, when
770 * rd is the zero register.
771 */
772 switch (op2) {
773 case 20:/* subcc */
774 case 60:/* save */
775 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 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 }
943
944
945 if (x64 && cpu->is_32bit) {
946 fatal("TODO: 64-bit instr on 32-bit cpu\n");
947 goto bad;
948 }
949
950
951 #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