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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 45428 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

1 /*
2 * Copyright (C) 2007 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_m88k_instr.c,v 1.42 2007/06/28 13:36:46 debug Exp $
29 *
30 * M88K 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 #define SYNCH_PC { \
40 int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page) \
41 / sizeof(struct m88k_instr_call); \
42 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) \
43 << M88K_INSTR_ALIGNMENT_SHIFT); \
44 cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT); \
45 }
46
47
48 /*
49 * nop: Do nothing.
50 */
51 X(nop)
52 {
53 }
54
55
56 /*
57 * br_samepage: Branch (to within the same translated page)
58 * bsr_samepage: Branch to subroutine (to within the same translated page)
59 *
60 * arg[0] = pointer to new instr_call
61 * arg[2] = offset to return address, from start of page
62 */
63 X(br_samepage)
64 {
65 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0];
66 }
67 X(bsr_samepage)
68 {
69 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc &
70 ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT))
71 + ic->arg[2];
72 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0];
73 }
74
75
76 /*
77 * br: Branch (to a different translated page)
78 * br.n: Branch (to a different translated page) with delay slot
79 * bsr: Branch to subroutine (to a different translated page)
80 * bsr.n: Branch to subroutine (to a different page) with delay slot
81 *
82 * arg[1] = relative offset from start of page
83 * arg[2] = offset to return address, from start of page
84 */
85 X(br)
86 {
87 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]);
88 quick_pc_to_pointers(cpu);
89 }
90 X(br_n)
91 {
92 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
93 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[1];
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 = cpu->cd.m88k.delay_target;
101 quick_pc_to_pointers(cpu);
102 } else
103 cpu->delay_slot = NOT_DELAYED;
104 }
105 X(bsr)
106 {
107 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
108 M88K_INSTR_ALIGNMENT_SHIFT);
109 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2];
110 cpu->pc = (uint32_t) (cpu->pc + ic->arg[1]);
111 quick_pc_to_pointers(cpu);
112 }
113 X(bsr_n)
114 {
115 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
116 M88K_INSTR_ALIGNMENT_SHIFT);
117 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2] + 4;
118 cpu->cd.m88k.delay_target = cpu->pc + ic->arg[1];
119 cpu->delay_slot = TO_BE_DELAYED;
120 ic[1].f(cpu, ic+1);
121 cpu->n_translated_instrs ++;
122 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
123 /* Note: Must be non-delayed when jumping to the new pc: */
124 cpu->delay_slot = NOT_DELAYED;
125 cpu->pc = cpu->cd.m88k.delay_target;
126 quick_pc_to_pointers(cpu);
127 } else
128 cpu->delay_slot = NOT_DELAYED;
129 }
130 X(bsr_trace)
131 {
132 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
133 M88K_INSTR_ALIGNMENT_SHIFT);
134 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2];
135 cpu->pc = (uint32_t) (cpu->pc + ic->arg[1]);
136 cpu_functioncall_trace(cpu, cpu->pc);
137 quick_pc_to_pointers(cpu);
138 }
139 X(bsr_n_trace)
140 {
141 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
142 M88K_INSTR_ALIGNMENT_SHIFT);
143 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2] + 4;
144 cpu->cd.m88k.delay_target = cpu->pc + ic->arg[1];
145 cpu->delay_slot = TO_BE_DELAYED;
146 ic[1].f(cpu, ic+1);
147 cpu->n_translated_instrs ++;
148 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
149 /* Note: Must be non-delayed when jumping to the new pc: */
150 cpu->delay_slot = NOT_DELAYED;
151 cpu->pc = cpu->cd.m88k.delay_target;
152 cpu_functioncall_trace(cpu, cpu->pc);
153 quick_pc_to_pointers(cpu);
154 } else
155 cpu->delay_slot = NOT_DELAYED;
156 }
157
158
159 /*
160 * bb? Branch if a bit in a register is 0 or 1.
161 * bb?_samepage: Branch within the same translated page.
162 * bb?_n_*: With delay slot.
163 *
164 * arg[0] = pointer to source register to test (s1).
165 * arg[1] = uint32_t mask to test (e.g. 0x00010000 to test bit 16)
166 * arg[2] = offset from start of current page _OR_ pointer to new instr_call
167 */
168 X(bb0)
169 {
170 if (!(reg(ic->arg[0]) & ic->arg[1])) {
171 cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
172 quick_pc_to_pointers(cpu);
173 }
174 }
175 X(bb0_samepage)
176 {
177 if (!(reg(ic->arg[0]) & ic->arg[1]))
178 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2];
179 }
180 X(bb0_n)
181 {
182 int cond = !(reg(ic->arg[0]) & (uint32_t)ic->arg[1]);
183 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
184 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2];
185 cpu->delay_slot = TO_BE_DELAYED;
186 ic[1].f(cpu, ic+1);
187 cpu->n_translated_instrs ++;
188 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
189 /* Note: Must be non-delayed when jumping to the new pc: */
190 cpu->delay_slot = NOT_DELAYED;
191 if (cond) {
192 cpu->pc = cpu->cd.m88k.delay_target;
193 quick_pc_to_pointers(cpu);
194 } else
195 cpu->cd.m88k.next_ic ++;
196 } else
197 cpu->delay_slot = NOT_DELAYED;
198 }
199 X(bb1)
200 {
201 if (reg(ic->arg[0]) & ic->arg[1]) {
202 cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
203 quick_pc_to_pointers(cpu);
204 }
205 }
206 X(bb1_samepage)
207 {
208 if (reg(ic->arg[0]) & ic->arg[1])
209 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2];
210 }
211 X(bb1_n)
212 {
213 int cond = reg(ic->arg[0]) & ic->arg[1];
214 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
215 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2];
216 cpu->delay_slot = TO_BE_DELAYED;
217 ic[1].f(cpu, ic+1);
218 cpu->n_translated_instrs ++;
219 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
220 /* Note: Must be non-delayed when jumping to the new pc: */
221 cpu->delay_slot = NOT_DELAYED;
222 if (cond) {
223 cpu->pc = cpu->cd.m88k.delay_target;
224 quick_pc_to_pointers(cpu);
225 } else
226 cpu->cd.m88k.next_ic ++;
227 } else
228 cpu->delay_slot = NOT_DELAYED;
229 }
230
231
232 /*
233 * ff0, ff1: Find first cleared/set bit in a register
234 *
235 * arg[0] = pointer to register d
236 * arg[2] = pointer to register s2
237 */
238 X(ff0)
239 {
240 uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]);
241 int n = 31;
242
243 for (;;) {
244 if (!(s2 & mask)) {
245 reg(ic->arg[0]) = n;
246 return;
247 }
248 mask >>= 1; n--;
249 if (mask == 0) {
250 reg(ic->arg[0]) = 32;
251 return;
252 }
253 }
254 }
255 X(ff1)
256 {
257 uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]);
258 int n = 31;
259
260 for (;;) {
261 if (s2 & mask) {
262 reg(ic->arg[0]) = n;
263 return;
264 }
265 mask >>= 1; n--;
266 if (mask == 0) {
267 reg(ic->arg[0]) = 32;
268 return;
269 }
270 }
271 }
272
273
274 /* Include all automatically generated bcnd and bcnd.n instructions: */
275 #include "tmp_m88k_bcnd.c"
276
277
278 /* Include all automatically generated load/store instructions: */
279 #include "tmp_m88k_loadstore.c"
280 #define M88K_LOADSTORE_STORE 4
281 #define M88K_LOADSTORE_SIGNEDNESS 8
282 #define M88K_LOADSTORE_ENDIANNESS 16
283 #define M88K_LOADSTORE_SCALEDNESS 32
284 #define M88K_LOADSTORE_USR 64
285 #define M88K_LOADSTORE_REGISTEROFFSET 128
286
287
288 /*
289 * jmp: Jump to register
290 * jmp.n: Jump to register, with delay slot
291 * jsr: Jump to register, set r1 to return address
292 * jsr.n: Jump to register, set r1 to return address, with delay slot
293 *
294 * arg[1] = offset to return address, from start of current page
295 * arg[2] = pointer to register s2
296 */
297 X(jmp)
298 {
299 cpu->pc = reg(ic->arg[2]) & ~3;
300 quick_pc_to_pointers(cpu);
301 }
302 X(jmp_n)
303 {
304 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
305 cpu->delay_slot = TO_BE_DELAYED;
306 ic[1].f(cpu, ic+1);
307 cpu->n_translated_instrs ++;
308 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
309 /* Note: Must be non-delayed when jumping to the new pc: */
310 cpu->delay_slot = NOT_DELAYED;
311 cpu->pc = cpu->cd.m88k.delay_target;
312 quick_pc_to_pointers(cpu);
313 } else
314 cpu->delay_slot = NOT_DELAYED;
315 }
316 X(jmp_trace)
317 {
318 cpu->pc = reg(ic->arg[2]) & ~3;
319 cpu_functioncall_trace_return(cpu);
320 quick_pc_to_pointers(cpu);
321 }
322 X(jmp_n_trace)
323 {
324 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
325 cpu->delay_slot = TO_BE_DELAYED;
326 ic[1].f(cpu, ic+1);
327 cpu->n_translated_instrs ++;
328 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
329 /* Note: Must be non-delayed when jumping to the new pc: */
330 cpu->delay_slot = NOT_DELAYED;
331 cpu->pc = cpu->cd.m88k.delay_target;
332 cpu_functioncall_trace_return(cpu);
333 quick_pc_to_pointers(cpu);
334 } else
335 cpu->delay_slot = NOT_DELAYED;
336 }
337 X(jsr)
338 {
339 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
340 cpu->pc = reg(ic->arg[2]) & ~3;
341 quick_pc_to_pointers(cpu);
342 }
343 X(jsr_n)
344 {
345 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
346 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
347 cpu->delay_slot = TO_BE_DELAYED;
348 ic[1].f(cpu, ic+1);
349 cpu->n_translated_instrs ++;
350 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
351 /* Note: Must be non-delayed when jumping to the new pc: */
352 cpu->delay_slot = NOT_DELAYED;
353 cpu->pc = cpu->cd.m88k.delay_target;
354 quick_pc_to_pointers(cpu);
355 } else
356 cpu->delay_slot = NOT_DELAYED;
357 }
358 X(jsr_trace)
359 {
360 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
361 cpu->pc = reg(ic->arg[2]) & ~3;
362 cpu_functioncall_trace(cpu, cpu->pc);
363 quick_pc_to_pointers(cpu);
364 }
365 X(jsr_n_trace)
366 {
367 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
368 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
369 cpu->delay_slot = TO_BE_DELAYED;
370 ic[1].f(cpu, ic+1);
371 cpu->n_translated_instrs ++;
372 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
373 /* Note: Must be non-delayed when jumping to the new pc: */
374 cpu->delay_slot = NOT_DELAYED;
375 cpu->pc = cpu->cd.m88k.delay_target;
376 cpu_functioncall_trace(cpu, cpu->pc);
377 quick_pc_to_pointers(cpu);
378 } else
379 cpu->delay_slot = NOT_DELAYED;
380 }
381
382
383 /*
384 * cmp_imm: Compare S1 with immediate value.
385 * cmp: Compare S1 with S2.
386 *
387 * arg[0] = pointer to register d
388 * arg[1] = pointer to register s1
389 * arg[2] = pointer to register s2 or imm
390 */
391 static void m88k_cmp(struct cpu *cpu, struct m88k_instr_call *ic, uint32_t y)
392 {
393 uint32_t x = reg(ic->arg[1]);
394 uint32_t r;
395
396 if (x == y) {
397 r = M88K_CMP_HS | M88K_CMP_LS | M88K_CMP_GE
398 | M88K_CMP_LE | M88K_CMP_EQ;
399 } else {
400 if (x > y)
401 r = M88K_CMP_NE | M88K_CMP_HS | M88K_CMP_HI;
402 else
403 r = M88K_CMP_NE | M88K_CMP_LO | M88K_CMP_LS;
404 if ((int32_t)x > (int32_t)y)
405 r |= M88K_CMP_GE | M88K_CMP_GT;
406 else
407 r |= M88K_CMP_LT | M88K_CMP_LE;
408 }
409
410 reg(ic->arg[0]) = r;
411 }
412 X(cmp_imm) { m88k_cmp(cpu, ic, ic->arg[2]); }
413 X(cmp) { m88k_cmp(cpu, ic, reg(ic->arg[2])); }
414
415
416 /*
417 * extu_imm: Extract bits, unsigned, immediate W<O>.
418 * extu: Extract bits, unsigned, W<O> taken from register s2.
419 * ext_imm: Extract bits, signed, immediate W<O>.
420 * ext: Extract bits, signed, W<O> taken from register s2.
421 * mak_imm: Make bit field, immediate W<O>.
422 * mak: Make bit field, W<O> taken from register s2.
423 * clr: Clear bits, W<O> taken from register s2.
424 * set: Set bits, W<O> taken from register s2.
425 *
426 * arg[0] = pointer to register d
427 * arg[1] = pointer to register s1
428 * arg[2] = pointer to register s2 or 10 bits wwwwwooooo
429 */
430 static void m88k_extu(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
431 {
432 uint32_t x = reg(ic->arg[1]) >> o;
433 if (w != 0) {
434 x <<= (32-w);
435 x >>= (32-w);
436 }
437 reg(ic->arg[0]) = x;
438 }
439 static void m88k_ext(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
440 {
441 int32_t x = reg(ic->arg[1]) >> o;
442 if (w != 0) {
443 x <<= (32-w);
444 x >>= (32-w);
445 }
446 reg(ic->arg[0]) = x;
447 }
448 static void m88k_mak(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
449 {
450 uint32_t x = reg(ic->arg[1]);
451 if (w != 0) {
452 x <<= (32-w);
453 x >>= (32-w);
454 }
455 reg(ic->arg[0]) = x << o;
456 }
457 X(extu_imm)
458 {
459 m88k_extu(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
460 }
461 X(extu)
462 {
463 m88k_extu(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
464 reg(ic->arg[2]) & 0x1f);
465 }
466 X(ext_imm)
467 {
468 m88k_ext(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
469 }
470 X(ext)
471 {
472 m88k_ext(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
473 reg(ic->arg[2]) & 0x1f);
474 }
475 X(mak_imm)
476 {
477 m88k_mak(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
478 }
479 X(mak)
480 {
481 m88k_mak(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
482 reg(ic->arg[2]) & 0x1f);
483 }
484 X(clr)
485 {
486 int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f;
487 uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1;
488 x <<= o;
489 reg(ic->arg[0]) = reg(ic->arg[1]) & ~x;
490 }
491 X(set)
492 {
493 int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f;
494 uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1;
495 x <<= o;
496 reg(ic->arg[0]) = reg(ic->arg[1]) | x;
497 }
498
499
500 /*
501 * or_r0_imm0: d = 0 (optimized case when s1 = r0, imm = 0)
502 * or_r0_imm: d = imm (optimized case when s1 = r0)
503 * or_imm: d = s1 | imm
504 * xor_imm: d = s1 ^ imm
505 * and_imm: d = (s1 & imm) | (s1 & 0xffff0000)
506 * and_u_imm: d = (s1 & imm) | (s1 & 0xffff)
507 * mask_imm: d = s1 & imm
508 * addu_imm: d = s1 + imm
509 * subu_imm: d = s1 - imm
510 * inc_reg: d ++; (addu special case; d = d + 1)
511 * dec_reg: d --; (subu special case; d = d - 1)
512 * mulu_imm: d = s1 * imm
513 * divu_imm: d = s1 / imm (unsigned)
514 * div_imm: d = s1 / imm (signed)
515 * sub_imm: d = s1 - imm (subtraction with overflow exception)
516 *
517 * arg[0] = pointer to register d
518 * arg[1] = pointer to register s1
519 * arg[2] = imm
520 */
521 X(or_r0_imm0) { reg(ic->arg[0]) = 0; }
522 X(or_r0_imm) { reg(ic->arg[0]) = ic->arg[2]; }
523 X(or_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) | ic->arg[2]; }
524 X(xor_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ ic->arg[2]; }
525 X(and_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2])
526 | (reg(ic->arg[1]) & 0xffff0000); }
527 X(and_u_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2])
528 | (reg(ic->arg[1]) & 0xffff); }
529 X(mask_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) & ic->arg[2]; }
530 X(addu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) + ic->arg[2]; }
531 X(subu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) - ic->arg[2]; }
532 X(inc_reg) { reg(ic->arg[0]) ++; }
533 X(dec_reg) { reg(ic->arg[0]) --; }
534 X(mulu_imm)
535 {
536 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
537 SYNCH_PC;
538 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
539 } else
540 reg(ic->arg[0]) = reg(ic->arg[1]) * ic->arg[2];
541 }
542 X(divu_imm)
543 {
544 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
545 SYNCH_PC;
546 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
547 } else if (ic->arg[2] == 0) {
548 SYNCH_PC;
549 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
550 } else
551 reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / ic->arg[2];
552 }
553 X(div_imm)
554 {
555 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
556 SYNCH_PC;
557 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
558 } else if (ic->arg[2] == 0) {
559 SYNCH_PC;
560 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
561 } else
562 reg(ic->arg[0]) = (int32_t) reg(ic->arg[1]) / ic->arg[2];
563 }
564 X(sub_imm)
565 {
566 int32_t a = reg(ic->arg[1]);
567 int32_t b = ic->arg[2];
568 int32_t res = a - b;
569
570 if (a < 0 && res >= 0) {
571 SYNCH_PC;
572 m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0);
573 return;
574 }
575
576 reg(ic->arg[0]) = res;
577 }
578
579
580 /*
581 * or: d = s1 | s2
582 * or_c: d = s1 | ~s2
583 * or_r0: d = s2
584 * xor: d = s1 ^ s2
585 * xor_c: d = s1 ^ ~s2
586 * and: d = s1 & s2
587 * and_c: d = s1 & ~s2
588 * addu: d = s1 + s2
589 * addu_co: d = s1 + s2 carry out
590 * addu_ci: d = s1 + s2 + carry carry in
591 * lda_reg_X: same as addu, but s2 is scaled by 2, 4, or 8
592 * subu: d = s1 - s2
593 * subu_co: d = s1 - s2 carry/borrow out
594 * subu_ci: d = s1 - s2 - (carry? 0 : 1) carry in
595 * mul: d = s1 * s2
596 * divu: d = s1 / s2 (unsigned)
597 * div: d = s1 / s2 (signed)
598 *
599 * arg[0] = pointer to register d
600 * arg[1] = pointer to register s1
601 * arg[2] = pointer to register s2
602 */
603 X(or) { reg(ic->arg[0]) = reg(ic->arg[1]) | reg(ic->arg[2]); }
604 X(or_c) { reg(ic->arg[0]) = reg(ic->arg[1]) | ~(reg(ic->arg[2])); }
605 X(or_r0){ reg(ic->arg[0]) = reg(ic->arg[2]); }
606 X(xor) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ reg(ic->arg[2]); }
607 X(xor_c){ reg(ic->arg[0]) = reg(ic->arg[1]) ^ ~(reg(ic->arg[2])); }
608 X(and) { reg(ic->arg[0]) = reg(ic->arg[1]) & reg(ic->arg[2]); }
609 X(and_c){ reg(ic->arg[0]) = reg(ic->arg[1]) & ~(reg(ic->arg[2])); }
610 X(addu) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]); }
611 X(addu_s2r0) { reg(ic->arg[0]) = reg(ic->arg[1]); }
612 X(lda_reg_2) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 2; }
613 X(lda_reg_4) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 4; }
614 X(lda_reg_8) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 8; }
615 X(subu) { reg(ic->arg[0]) = reg(ic->arg[1]) - reg(ic->arg[2]); }
616 X(mul)
617 {
618 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
619 SYNCH_PC;
620 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
621 } else
622 reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
623 }
624 X(divu)
625 {
626 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
627 SYNCH_PC;
628 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
629 } else if (reg(ic->arg[2]) == 0) {
630 SYNCH_PC;
631 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
632 } else
633 reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / reg(ic->arg[2]);
634 }
635 X(div)
636 {
637 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
638 SYNCH_PC;
639 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
640 } else if (reg(ic->arg[2]) == 0) {
641 SYNCH_PC;
642 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
643 } else
644 reg(ic->arg[0]) = (int32_t) reg(ic->arg[1]) / reg(ic->arg[2]);
645 }
646 X(addu_co)
647 {
648 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]);
649 a += b;
650 reg(ic->arg[0]) = a;
651 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
652 if ((a >> 32) & 1)
653 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
654 }
655 X(addu_ci)
656 {
657 uint32_t result = reg(ic->arg[1]) + reg(ic->arg[2]);
658 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C)
659 result ++;
660 reg(ic->arg[0]) = result;
661 }
662 X(subu_co)
663 {
664 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]);
665 a -= b;
666 reg(ic->arg[0]) = a;
667 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
668 if ((a >> 32) & 1)
669 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
670 }
671 X(subu_ci)
672 {
673 uint32_t result = reg(ic->arg[1]) - reg(ic->arg[2]);
674 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C))
675 result --;
676 reg(ic->arg[0]) = result;
677 }
678
679
680 /*
681 * ldcr: Load value from a control register, store in register d.
682 * fldcr: Load value from a floating point control register, store in reg d.
683 *
684 * arg[0] = pointer to register d
685 * arg[1] = 6-bit control register number
686 */
687 X(ldcr)
688 {
689 SYNCH_PC;
690
691 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
692 m88k_ldcr(cpu, (uint32_t *) (void *) ic->arg[0], ic->arg[1]);
693 else
694 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
695 }
696 X(fldcr)
697 {
698 SYNCH_PC;
699
700 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62)
701 reg(ic->arg[0]) = cpu->cd.m88k.fcr[ic->arg[1]];
702 else {
703 /* TODO: The manual says "floating point privilege
704 violation", not just "privilege violation"! */
705 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
706 }
707 }
708
709
710 /*
711 * stcr: Store a value into a control register.
712 * fstcr: Store a value into a floating point control register.
713 *
714 * arg[0] = pointer to source register
715 * arg[1] = 6-bit control register number
716 */
717 X(stcr)
718 {
719 SYNCH_PC;
720
721 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
722 m88k_stcr(cpu, reg(ic->arg[0]), ic->arg[1], 0);
723 else
724 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
725 }
726 X(fstcr)
727 {
728 SYNCH_PC;
729
730 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62)
731 m88k_fstcr(cpu, reg(ic->arg[0]), ic->arg[1]);
732 else {
733 /* TODO: The manual says "floating point privilege
734 violation", not just "privilege violation"! */
735 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
736 }
737 }
738
739
740 /*
741 * xcr: Exchange (load + store) control register.
742 *
743 * arg[0] = pointer to register d
744 * arg[1] = pointer to register s1
745 * arg[2] = 6-bit control register number
746 */
747 X(xcr)
748 {
749 uint32_t tmp, tmp2;
750 SYNCH_PC;
751
752 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) {
753 tmp = reg(ic->arg[1]);
754 m88k_ldcr(cpu, &tmp2, ic->arg[2]);
755 m88k_stcr(cpu, tmp, ic->arg[2], 0);
756 reg(ic->arg[0]) = tmp2;
757 } else
758 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
759 }
760
761
762 /*
763 * rte: Return from exception
764 */
765 X(rte)
766 {
767 /* If executed from user mode, then cause an exception: */
768 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) {
769 SYNCH_PC;
770 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
771 return;
772 }
773
774 m88k_stcr(cpu, cpu->cd.m88k.cr[M88K_CR_EPSR], M88K_CR_PSR, 1);
775
776 /* First try the NIP, if it is Valid: */
777 cpu->pc = cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR;
778 if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_E) {
779 fatal("rte: NIP: TODO: single-step support\n");
780 goto abort_dump;
781 }
782
783 if (cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_E) {
784 fatal("rte: TODO: FIP single-step support\n");
785 goto abort_dump;
786 }
787
788 if ((cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR)
789 == (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR)) {
790 cpu->cd.m88k.cr[M88K_CR_SFIP] = cpu->pc + 4;
791 }
792
793 if ((cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR)
794 != (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR) + 4) {
795 /*
796 * The NIP instruction should first be executed (this
797 * is the one the exception handler choose to return to),
798 * and then the FIP instruction should run (the target
799 * of a delayed branch).
800 */
801
802 fatal("FIP != NIP + 4: TODO\n");
803 goto abort_dump;
804 }
805
806 quick_pc_to_pointers(cpu);
807 return;
808
809 abort_dump:
810 fatal("NIP=0x%08"PRIx32", FIP=0x%08"PRIx32"\n",
811 cpu->cd.m88k.cr[M88K_CR_SNIP], cpu->cd.m88k.cr[M88K_CR_SFIP]);
812 exit(1);
813 }
814
815
816 /*
817 * xmem_slow: Unoptimized xmem (exchange register with memory)
818 *
819 * arg[0] = copy of the instruction word
820 */
821 X(xmem_slow)
822 {
823 uint32_t iword = ic->arg[0], addr;
824 uint8_t tmp[4];
825 uint8_t data[4];
826 int d = (iword >> 21) & 0x1f;
827 int s1 = (iword >> 16) & 0x1f;
828 int s2 = iword & 0x1f;
829 int imm16 = iword & 0xffff;
830 int scaled = iword & 0x200;
831 int size = iword & 0x400;
832 int user = iword & 0x80;
833
834 SYNCH_PC;
835
836 if (user) {
837 fatal("xmem_slow: user: not yet (TODO)\n");
838 exit(1);
839 }
840
841 if ((iword & 0xf0000000) == 0) {
842 /* immediate offset: */
843 addr = imm16;
844 scaled = 0;
845 size = (iword >> 26) & 1;
846 user = 0;
847 } else {
848 /* register offset: */
849 addr = cpu->cd.m88k.r[s2];
850 if (scaled && size)
851 addr *= sizeof(uint32_t);
852 }
853
854 addr += cpu->cd.m88k.r[s1];
855
856 if (size) {
857 uint32_t x = cpu->cd.m88k.r[d];
858 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
859 x = LE32_TO_HOST(x);
860 else
861 x = BE32_TO_HOST(x);
862 *((uint32_t *)&tmp[0]) = x;
863
864 if (addr & 3) {
865 m88k_exception(cpu,
866 M88K_EXCEPTION_MISALIGNED_ACCESS, 0);
867 return;
868 }
869 } else
870 tmp[0] = cpu->cd.m88k.r[d];
871
872 if (!cpu->memory_rw(cpu, cpu->mem, addr, (uint8_t *) &data,
873 size? 4 : 1, MEM_READ, CACHE_DATA)) {
874 /* Exception. */
875
876 fatal("XMEM exception: TODO: update the transaction"
877 " registers!\n");
878 exit(1);
879 /* return; */
880 }
881
882 if (!cpu->memory_rw(cpu, cpu->mem, addr, (uint8_t *) &tmp,
883 size? 4 : 1, MEM_WRITE, CACHE_DATA)) {
884 /* Exception. */
885
886 fatal("XMEM exception: TODO: update the transaction"
887 " registers!\n");
888 exit(1);
889 /* return; */
890 }
891
892 if (size) {
893 uint32_t x = *((uint32_t *)&data[0]);
894 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
895 x = LE32_TO_HOST(x);
896 else
897 x = BE32_TO_HOST(x);
898 cpu->cd.m88k.r[d] = x;
899 } else
900 cpu->cd.m88k.r[d] = data[0];
901 }
902
903
904 /*
905 * prom-call:
906 */
907 X(prom_call)
908 {
909 /* If executed from user mode, then cause an exception: */
910 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) {
911 SYNCH_PC;
912 m88k_exception(cpu, M88K_EXCEPTION_UNIMPLEMENTED_OPCODE, 0);
913 return;
914 }
915
916 switch (cpu->machine->machine_type) {
917 case MACHINE_MVME88K:
918 mvmeprom_emul(cpu);
919 break;
920 default:fatal("m88k prom_call: unimplemented machine type\n");
921 exit(1);
922 }
923
924 if (!cpu->running) {
925 cpu->n_translated_instrs --;
926 cpu->cd.m88k.next_ic = &nothing_call;
927 }
928 }
929
930
931 /*
932 * tb0, tb1: Trap on bit Clear/Set
933 *
934 * arg[0] = bitmask to check (e.g. 0x00020000 for bit 17)
935 * arg[1] = pointer to register s1
936 * arg[2] = 9-bit vector number
937 */
938 X(tb0)
939 {
940 SYNCH_PC;
941
942 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
943 && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) {
944 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
945 return;
946 }
947
948 if (!(reg(ic->arg[1]) & ic->arg[0]))
949 m88k_exception(cpu, ic->arg[2], 1);
950 }
951 X(tb1)
952 {
953 SYNCH_PC;
954
955 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
956 && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) {
957 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
958 return;
959 }
960
961 if (reg(ic->arg[1]) & ic->arg[0])
962 m88k_exception(cpu, ic->arg[2], 1);
963 }
964
965
966 /*****************************************************************************/
967
968
969 X(end_of_page)
970 {
971 /* Update the PC: (offset 0, but on the next page) */
972 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
973 M88K_INSTR_ALIGNMENT_SHIFT);
974 cpu->pc += (M88K_IC_ENTRIES_PER_PAGE << M88K_INSTR_ALIGNMENT_SHIFT);
975
976 /* end_of_page doesn't count as an executed instruction: */
977 cpu->n_translated_instrs --;
978
979 /*
980 * Find the new physpage and update translation pointers.
981 *
982 * Note: This may cause an exception, if e.g. the new page is
983 * not accessible.
984 */
985 quick_pc_to_pointers(cpu);
986
987 /* Simple jump to the next page (if we are lucky): */
988 if (cpu->delay_slot == NOT_DELAYED)
989 return;
990
991 /*
992 * If we were in a delay slot, and we got an exception while doing
993 * quick_pc_to_pointers, then return. The function which called
994 * end_of_page should handle this case.
995 */
996 if (cpu->delay_slot == EXCEPTION_IN_DELAY_SLOT)
997 return;
998
999 /*
1000 * Tricky situation; the delay slot is on the next virtual page.
1001 * Calling to_be_translated will translate one instruction manually,
1002 * execute it, and then discard it.
1003 */
1004 /* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */
1005
1006 instr(to_be_translated)(cpu, cpu->cd.m88k.next_ic);
1007
1008 /* The instruction in the delay slot has now executed. */
1009 /* fatal("[ end_of_page: back from executing the delay slot, %i ]\n",
1010 cpu->delay_slot); */
1011
1012 /* Find the physpage etc of the instruction in the delay slot
1013 (or, if there was an exception, the exception handler): */
1014 quick_pc_to_pointers(cpu);
1015 }
1016
1017
1018 X(end_of_page2)
1019 {
1020 /* Synchronize PC on the _second_ instruction on the next page: */
1021 int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page)
1022 / sizeof(struct m88k_instr_call);
1023 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1)
1024 << M88K_INSTR_ALIGNMENT_SHIFT);
1025 cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT);
1026
1027 if (low_pc < 0 || low_pc > ((M88K_IC_ENTRIES_PER_PAGE+1)
1028 << M88K_INSTR_ALIGNMENT_SHIFT)) {
1029 printf("[ end_of_page2: HUH? low_pc=%i, cpu->pc = %08"
1030 PRIx32" ]\n", low_pc, (uint32_t) cpu->pc);
1031 }
1032
1033 /* This doesn't count as an executed instruction. */
1034 cpu->n_translated_instrs --;
1035
1036 quick_pc_to_pointers(cpu);
1037
1038 if (cpu->delay_slot == NOT_DELAYED)
1039 return;
1040
1041 fatal("end_of_page2: fatal error, we're in a delay slot\n");
1042 exit(1);
1043 }
1044
1045
1046 /*****************************************************************************/
1047
1048
1049 /*
1050 * m88k_instr_to_be_translated():
1051 *
1052 * Translate an instruction word into a m88k_instr_call. ic is filled in with
1053 * valid data for the translated instruction, or a "nothing" instruction if
1054 * there was a translation failure. The newly translated instruction is then
1055 * executed.
1056 */
1057 X(to_be_translated)
1058 {
1059 uint32_t addr, low_pc, iword;
1060 unsigned char *page;
1061 unsigned char ib[4];
1062 uint32_t op26, op10, d, s1, s2, cr6, imm16;
1063 int32_t d16, d26, simm16;
1064 int offset, shift;
1065 int in_crosspage_delayslot = 0;
1066 void (*samepage_function)(struct cpu *, struct m88k_instr_call *)=NULL;
1067
1068 /* Figure out the (virtual) address of the instruction: */
1069 low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page)
1070 / sizeof(struct m88k_instr_call);
1071
1072 /* Special case for branch with delayslot on the next page: */
1073 if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) {
1074 /* fatal("[ delay-slot translation across page "
1075 "boundary ]\n"); */
1076 in_crosspage_delayslot = 1;
1077 }
1078
1079 addr = cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1)
1080 << M88K_INSTR_ALIGNMENT_SHIFT);
1081 addr += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT);
1082 cpu->pc = (MODE_int_t)addr;
1083 addr &= ~((1 << M88K_INSTR_ALIGNMENT_SHIFT) - 1);
1084
1085 /* Read the instruction word from memory: */
1086 page = cpu->cd.m88k.host_load[(uint32_t)addr >> 12];
1087
1088 if (page != NULL) {
1089 /* fatal("TRANSLATION HIT!\n"); */
1090 memcpy(ib, page + (addr & 0xffc), sizeof(ib));
1091 } else {
1092 /* fatal("TRANSLATION MISS!\n"); */
1093 if (!cpu->memory_rw(cpu, cpu->mem, addr, ib,
1094 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
1095 fatal("to_be_translated(): read failed: TODO\n");
1096 goto bad;
1097 }
1098 }
1099
1100 iword = *((uint32_t *)&ib[0]);
1101 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1102 iword = LE32_TO_HOST(iword);
1103 else
1104 iword = BE32_TO_HOST(iword);
1105
1106
1107 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
1108 #include "cpu_dyntrans.c"
1109 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
1110
1111
1112 /*
1113 * Translate the instruction:
1114 *
1115 * NOTE: _NEVER_ allow writes to the zero register; all instructions
1116 * that use the zero register as their destination should be treated
1117 * as NOPs, except those that access memory (they should use the
1118 * scratch register instead).
1119 */
1120 if (cpu->cd.m88k.r[M88K_ZERO_REG] != 0) {
1121 fatal("INTERNAL ERROR! M88K_ZERO_REG != 0?\n");
1122 exit(1);
1123 }
1124
1125 op26 = (iword >> 26) & 0x3f;
1126 op10 = (iword >> 10) & 0x3f;
1127 d = (iword >> 21) & 0x1f;
1128 s1 = (iword >> 16) & 0x1f;
1129 s2 = iword & 0x1f;
1130 imm16 = iword & 0xffff;
1131 simm16 = (int16_t) (iword & 0xffff);
1132 cr6 = (iword >> 5) & 0x3f;
1133 d16 = ((int16_t) (iword & 0xffff)) * 4;
1134 d26 = ((int32_t)((iword & 0x03ffffff) << 6)) >> 4;
1135
1136 switch (op26) {
1137
1138 case 0x00:
1139 case 0x01:
1140 ic->f = instr(xmem_slow);
1141 ic->arg[0] = iword;
1142 if (d == M88K_ZERO_REG)
1143 ic->f = instr(nop);
1144 if (iword == 0)
1145 goto bad;
1146 break;
1147
1148 case 0x02: /* ld.hu */
1149 case 0x03: /* ld.bu */
1150 case 0x04: /* ld.d */
1151 case 0x05: /* ld */
1152 case 0x06: /* ld.h */
1153 case 0x07: /* ld.b */
1154 case 0x08: /* st.d */
1155 case 0x09: /* st */
1156 case 0x0a: /* st.h */
1157 case 0x0b: /* st.b */
1158 {
1159 int store = 0, signedness = 0, opsize = 0;
1160
1161 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1162 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1163 ic->arg[2] = imm16;
1164
1165 switch (op26) {
1166 case 0x02: opsize = 1; break;
1167 case 0x03: opsize = 0; break;
1168 case 0x04: opsize = 3; break;
1169 case 0x05: opsize = 2; break;
1170 case 0x06: opsize = 1; signedness = 1; break;
1171 case 0x07: opsize = 0; signedness = 1; break;
1172 case 0x08: store = 1; opsize = 3; break;
1173 case 0x09: store = 1; opsize = 2; break;
1174 case 0x0a: store = 1; opsize = 1; break;
1175 case 0x0b: store = 1; opsize = 0; break;
1176 }
1177
1178 if (opsize == 3 && d == 31) {
1179 fatal("m88k load/store of register pair r31/r0"
1180 " is not yet implemented\n");
1181 goto bad;
1182 }
1183
1184 ic->f = m88k_loadstore[ opsize
1185 + (store? M88K_LOADSTORE_STORE : 0)
1186 + (signedness? M88K_LOADSTORE_SIGNEDNESS:0)
1187 + (cpu->byte_order == EMUL_BIG_ENDIAN?
1188 M88K_LOADSTORE_ENDIANNESS : 0) ];
1189 }
1190 break;
1191
1192 case 0x10: /* and imm */
1193 case 0x11: /* and.u imm */
1194 case 0x12: /* mask imm */
1195 case 0x13: /* mask.u imm */
1196 case 0x14: /* xor imm */
1197 case 0x15: /* xor.u imm */
1198 case 0x16: /* or imm */
1199 case 0x17: /* or.u imm */
1200 case 0x18: /* addu imm */
1201 case 0x19: /* subu imm */
1202 case 0x1a: /* divu imm */
1203 case 0x1b: /* mulu imm */
1204 case 0x1d: /* sub imm */
1205 case 0x1e: /* div imm */
1206 case 0x1f: /* cmp imm */
1207 shift = 0;
1208 switch (op26) {
1209 case 0x10: ic->f = instr(and_imm); break;
1210 case 0x11: ic->f = instr(and_u_imm); shift = 16; break;
1211 case 0x12: ic->f = instr(mask_imm); break;
1212 case 0x13: ic->f = instr(mask_imm); shift = 16; break;
1213 case 0x14: ic->f = instr(xor_imm); break;
1214 case 0x15: ic->f = instr(xor_imm); shift = 16; break;
1215 case 0x16: ic->f = instr(or_imm); break;
1216 case 0x17: ic->f = instr(or_imm); shift = 16; break;
1217 case 0x18: ic->f = instr(addu_imm); break;
1218 case 0x19: ic->f = instr(subu_imm); break;
1219 case 0x1a: ic->f = instr(divu_imm); break;
1220 case 0x1b: ic->f = instr(mulu_imm); break;
1221 case 0x1d: ic->f = instr(sub_imm); break;
1222 case 0x1e: ic->f = instr(div_imm); break;
1223 case 0x1f: ic->f = instr(cmp_imm); break;
1224 }
1225
1226 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1227 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1228 ic->arg[2] = imm16 << shift;
1229
1230 /* Optimization for or d,r0,imm and similar */
1231 if (s1 == M88K_ZERO_REG && ic->f == instr(or_imm)) {
1232 if (ic->arg[2] == 0)
1233 ic->f = instr(or_r0_imm0);
1234 else
1235 ic->f = instr(or_r0_imm);
1236 }
1237 if (ic->arg[2] == 0 && ic->f == instr(addu_imm))
1238 ic->f = instr(addu_s2r0);
1239
1240 if (d == s1 && ic->arg[2] == 1) {
1241 if (ic->f == instr(addu_imm))
1242 ic->f = instr(inc_reg);
1243 if (ic->f == instr(subu_imm))
1244 ic->f = instr(dec_reg);
1245 }
1246
1247 if (d == M88K_ZERO_REG)
1248 ic->f = instr(nop);
1249 break;
1250
1251 case 0x20:
1252 if ((iword & 0x001ff81f) == 0x00004000) {
1253 ic->f = instr(ldcr);
1254 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1255 ic->arg[1] = cr6;
1256 if (d == M88K_ZERO_REG)
1257 ic->arg[0] = (size_t)
1258 &cpu->cd.m88k.zero_scratch;
1259 } else if ((iword & 0x001ff81f) == 0x00004800) {
1260 ic->f = instr(fldcr);
1261 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1262 ic->arg[1] = cr6;
1263 if (d == M88K_ZERO_REG)
1264 ic->arg[0] = (size_t)
1265 &cpu->cd.m88k.zero_scratch;
1266 } else if ((iword & 0x03e0f800) == 0x00008000) {
1267 ic->f = instr(stcr);
1268 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1269 ic->arg[1] = cr6;
1270 if (s1 != s2)
1271 goto bad;
1272 } else if ((iword & 0x03e0f800) == 0x00008800) {
1273 ic->f = instr(fstcr);
1274 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1275 ic->arg[1] = cr6;
1276 if (s1 != s2)
1277 goto bad;
1278 } else if ((iword & 0x0000f800) == 0x0000c000) {
1279 ic->f = instr(xcr);
1280 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1281 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1282 ic->arg[2] = cr6;
1283 if (s1 != s2)
1284 goto bad;
1285 } else
1286 goto bad;
1287 break;
1288
1289 case 0x30: /* br */
1290 case 0x31: /* br.n */
1291 case 0x32: /* bsr */
1292 case 0x33: /* bsr.n */
1293 switch (op26) {
1294 case 0x30:
1295 ic->f = instr(br);
1296 samepage_function = instr(br_samepage);
1297 if (cpu->translation_readahead > 1)
1298 cpu->translation_readahead = 1;
1299 break;
1300 case 0x31:
1301 ic->f = instr(br_n);
1302 if (cpu->translation_readahead > 2)
1303 cpu->translation_readahead = 2;
1304 break;
1305 case 0x32:
1306 ic->f = instr(bsr);
1307 samepage_function = instr(bsr_samepage);
1308 break;
1309 case 0x33:
1310 ic->f = instr(bsr_n);
1311 break;
1312 }
1313
1314 offset = (addr & 0xffc) + d26;
1315
1316 /* Prepare both samepage and offset style args.
1317 (Only one will be used in the actual instruction.) */
1318 ic->arg[0] = (size_t) ( cpu->cd.m88k.cur_ic_page +
1319 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1320 ic->arg[1] = offset;
1321 ic->arg[2] = (addr & 0xffc) + 4; /* Return offset
1322 for bsr_samepage */
1323
1324 if (offset >= 0 && offset <= 0xffc &&
1325 samepage_function != NULL)
1326 ic->f = samepage_function;
1327
1328 if (cpu->machine->show_trace_tree) {
1329 if (op26 == 0x32)
1330 ic->f = instr(bsr_trace);
1331 if (op26 == 0x33)
1332 ic->f = instr(bsr_n_trace);
1333 }
1334
1335 break;
1336
1337 case 0x34: /* bb0 */
1338 case 0x35: /* bb0.n */
1339 case 0x36: /* bb1 */
1340 case 0x37: /* bb1.n */
1341 switch (op26) {
1342 case 0x34:
1343 ic->f = instr(bb0);
1344 samepage_function = instr(bb0_samepage);
1345 break;
1346 case 0x35:
1347 ic->f = instr(bb0_n);
1348 break;
1349 case 0x36:
1350 ic->f = instr(bb1);
1351 samepage_function = instr(bb1_samepage);
1352 break;
1353 case 0x37:
1354 ic->f = instr(bb1_n);
1355 break;
1356 }
1357
1358 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1359 ic->arg[1] = (uint32_t) (1 << d);
1360
1361 offset = (addr & 0xffc) + d16;
1362 ic->arg[2] = offset;
1363
1364 if (offset >= 0 && offset <= 0xffc &&
1365 samepage_function != NULL) {
1366 ic->f = samepage_function;
1367 ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page +
1368 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1369 }
1370 break;
1371
1372 case 0x3a: /* bcnd */
1373 case 0x3b: /* bcnd.n */
1374 ic->f = m88k_bcnd[d + 32 * (op26 & 1)];
1375 samepage_function = m88k_bcnd[64 + d + 32 * (op26 & 1)];
1376
1377 if (ic->f == NULL)
1378 goto bad;
1379
1380 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1381
1382 offset = (addr & 0xffc) + d16;
1383 ic->arg[2] = offset;
1384
1385 if (offset >= 0 && offset <= 0xffc &&
1386 samepage_function != NULL) {
1387 ic->f = samepage_function;
1388 ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page +
1389 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1390 }
1391 break;
1392
1393 case 0x3c:
1394 switch (op10) {
1395
1396 case 0x20: /* clr */
1397 case 0x22: /* set */
1398 case 0x24: /* ext */
1399 case 0x26: /* extu */
1400 case 0x28: /* mak */
1401 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1402 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1403 ic->arg[2] = iword & 0x3ff;
1404
1405 switch (op10) {
1406 case 0x20: ic->f = instr(mask_imm);
1407 {
1408 int w = ic->arg[2] >> 5;
1409 int o = ic->arg[2] & 0x1f;
1410 uint32_t x = w == 0? 0xffffffff
1411 : ((uint32_t)1 << w) - 1;
1412 x <<= o;
1413 ic->arg[2] = ~x;
1414 }
1415 break;
1416 case 0x22: ic->f = instr(or_imm);
1417 {
1418 int w = ic->arg[2] >> 5;
1419 int o = ic->arg[2] & 0x1f;
1420 uint32_t x = w == 0? 0xffffffff
1421 : ((uint32_t)1 << w) - 1;
1422 x <<= o;
1423 ic->arg[2] = x;
1424 }
1425 break;
1426 case 0x24: ic->f = instr(ext_imm); break;
1427 case 0x26: ic->f = instr(extu_imm); break;
1428 case 0x28: ic->f = instr(mak_imm); break;
1429 }
1430
1431 if (d == M88K_ZERO_REG)
1432 ic->f = instr(nop);
1433 break;
1434
1435 case 0x34: /* tb0 */
1436 case 0x36: /* tb1 */
1437 ic->arg[0] = 1 << d;
1438 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1439 ic->arg[2] = iword & 0x1ff;
1440 switch (op10) {
1441 case 0x34: ic->f = instr(tb0); break;
1442 case 0x36: ic->f = instr(tb1); break;
1443 }
1444 break;
1445
1446 default:goto bad;
1447 }
1448 break;
1449
1450 case 0x3d:
1451 if ((iword & 0xf000) <= 0x3fff ) {
1452 /* Load, Store, xmem, and lda: */
1453 int op = 0, opsize, user = 0, wt = 0;
1454 int signedness = 1, scaled = 0;
1455
1456 switch (iword & 0xf000) {
1457 case 0x2000: op = 1; /* st */ break;
1458 case 0x3000: op = 2; /* lda */ break;
1459 default: if ((iword & 0xf800) >= 0x0800)
1460 op = 0; /* ld */
1461 else
1462 op = 3; /* xmem */
1463 }
1464
1465 /* for (most) ld, st, lda: */
1466 opsize = (iword >> 10) & 3;
1467
1468 /* Turn opsize into x, where size = 1 << x: */
1469 opsize = 3 - opsize;
1470
1471 if (op == 3) {
1472 /* xmem: */
1473 switch ((iword >> 10) & 3) {
1474 case 0: opsize = 0; break;
1475 case 1: opsize = 2; break;
1476 default:fatal("Weird xmem opsize/type?\n");
1477 goto bad;
1478 }
1479 } else {
1480 if ((iword & 0xf800) == 0x800) {
1481 signedness = 0;
1482 if ((iword & 0xf00) < 0xc00)
1483 opsize = 1;
1484 else
1485 opsize = 0;
1486 } else {
1487 if (opsize >= 2 || op == 1)
1488 signedness = 0;
1489 }
1490 }
1491
1492 if (iword & 0x100)
1493 user = 1;
1494 if (iword & 0x80)
1495 wt = 1;
1496 if (iword & 0x200)
1497 scaled = 1;
1498
1499 if (wt) {
1500 fatal("wt bit not yet implemented! TODO\n");
1501 goto bad;
1502 }
1503
1504 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1505 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1506 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1507
1508 if (op == 0 || op == 1) {
1509 /* ld or st: */
1510 ic->f = m88k_loadstore[ opsize
1511 + (op==1? M88K_LOADSTORE_STORE : 0)
1512 + (signedness? M88K_LOADSTORE_SIGNEDNESS:0)
1513 + (cpu->byte_order == EMUL_BIG_ENDIAN?
1514 M88K_LOADSTORE_ENDIANNESS : 0)
1515 + (scaled? M88K_LOADSTORE_SCALEDNESS : 0)
1516 + (user? M88K_LOADSTORE_USR : 0)
1517 + M88K_LOADSTORE_REGISTEROFFSET ];
1518
1519 if (op == 0 && d == M88K_ZERO_REG)
1520 ic->f = instr(nop);
1521
1522 if (opsize == 3 && d == 31) {
1523 fatal("m88k load/store of register "
1524 "pair r31/r0: TODO\n");
1525 goto bad;
1526 }
1527 } else if (op == 2) {
1528 /* lda: */
1529 if (scaled) {
1530 switch (opsize) {
1531 case 0: ic->f = instr(addu); break;
1532 case 1: ic->f = instr(lda_reg_2); break;
1533 case 2: ic->f = instr(lda_reg_4); break;
1534 case 3: ic->f = instr(lda_reg_8); break;
1535 }
1536 } else {
1537 ic->f = instr(addu);
1538 }
1539 } else {
1540 /* xmem: */
1541 ic->f = instr(xmem_slow);
1542 ic->arg[0] = iword;
1543 if (d == M88K_ZERO_REG)
1544 ic->f = instr(nop);
1545 }
1546 } else switch ((iword >> 8) & 0xff) {
1547 case 0x40: /* and */
1548 case 0x44: /* and.c */
1549 case 0x50: /* xor */
1550 case 0x54: /* xor.c */
1551 case 0x58: /* or */
1552 case 0x5c: /* or.c */
1553 case 0x60: /* addu */
1554 case 0x61: /* addu.co */
1555 case 0x62: /* addu.ci */
1556 case 0x64: /* subu */
1557 case 0x65: /* subu.co */
1558 case 0x66: /* subu.ci */
1559 case 0x68: /* divu */
1560 case 0x6c: /* mul */
1561 case 0x78: /* div */
1562 case 0x7c: /* cmp */
1563 case 0x80: /* clr */
1564 case 0x88: /* set */
1565 case 0x90: /* ext */
1566 case 0x98: /* extu */
1567 case 0xa0: /* mak */
1568 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1569 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1570 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1571
1572 switch ((iword >> 8) & 0xff) {
1573 case 0x40: ic->f = instr(and); break;
1574 case 0x44: ic->f = instr(and_c); break;
1575 case 0x50: ic->f = instr(xor); break;
1576 case 0x54: ic->f = instr(xor_c); break;
1577 case 0x58: ic->f = instr(or); break;
1578 case 0x5c: ic->f = instr(or_c); break;
1579 case 0x60: ic->f = instr(addu); break;
1580 case 0x61: ic->f = instr(addu_co); break;
1581 case 0x62: ic->f = instr(addu_ci); break;
1582 case 0x64: ic->f = instr(subu); break;
1583 case 0x65: ic->f = instr(subu_co); break;
1584 case 0x66: ic->f = instr(subu_ci); break;
1585 case 0x68: ic->f = instr(divu); break;
1586 case 0x6c: ic->f = instr(mul); break;
1587 case 0x78: ic->f = instr(div); break;
1588 case 0x7c: ic->f = instr(cmp); break;
1589 case 0x80: ic->f = instr(clr); break;
1590 case 0x88: ic->f = instr(set); break;
1591 case 0x90: ic->f = instr(ext); break;
1592 case 0x98: ic->f = instr(extu); break;
1593 case 0xa0: ic->f = instr(mak); break;
1594 }
1595
1596 /* Optimization for or rX,r0,rY etc: */
1597 if (s1 == M88K_ZERO_REG && ic->f == instr(or))
1598 ic->f = instr(or_r0);
1599 if (s2 == M88K_ZERO_REG && ic->f == instr(addu))
1600 ic->f = instr(addu_s2r0);
1601 if (d == M88K_ZERO_REG)
1602 ic->f = instr(nop);
1603 break;
1604 case 0xc0: /* jmp */
1605 case 0xc4: /* jmp.n */
1606 case 0xc8: /* jsr */
1607 case 0xcc: /* jsr.n */
1608 switch ((iword >> 8) & 0xff) {
1609 case 0xc0: ic->f = instr(jmp);
1610 if (cpu->translation_readahead > 1)
1611 cpu->translation_readahead = 1;
1612 break;
1613 case 0xc4: ic->f = instr(jmp_n);
1614 if (cpu->translation_readahead > 2)
1615 cpu->translation_readahead = 2;
1616 break;
1617 case 0xc8: ic->f = instr(jsr); break;
1618 case 0xcc: ic->f = instr(jsr_n); break;
1619 }
1620
1621 ic->arg[1] = (addr & 0xffc) + 4;
1622 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1623
1624 if (((iword >> 8) & 0x04) == 0x04)
1625 ic->arg[1] = (addr & 0xffc) + 8;
1626
1627 if (cpu->machine->show_trace_tree &&
1628 s2 == M88K_RETURN_REG) {
1629 if (ic->f == instr(jmp))
1630 ic->f = instr(jmp_trace);
1631 if (ic->f == instr(jmp_n))
1632 ic->f = instr(jmp_n_trace);
1633 }
1634 if (cpu->machine->show_trace_tree) {
1635 if (ic->f == instr(jsr))
1636 ic->f = instr(jsr_trace);
1637 if (ic->f == instr(jsr_n))
1638 ic->f = instr(jsr_n_trace);
1639 }
1640 break;
1641 case 0xe8: /* ff1 */
1642 case 0xec: /* ff0 */
1643 switch ((iword >> 8) & 0xff) {
1644 case 0xe8: ic->f = instr(ff1); break;
1645 case 0xec: ic->f = instr(ff0); break;
1646 }
1647
1648 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1649 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1650
1651 if (d == M88K_ZERO_REG)
1652 ic->f = instr(nop);
1653 break;
1654 case 0xfc:
1655 switch (iword & 0xff) {
1656 case 0x00:
1657 ic->f = instr(rte);
1658 break;
1659 case (M88K_PROM_INSTR & 0xff):
1660 ic->f = instr(prom_call);
1661 break;
1662 default:fatal("Unimplemented 3d/fc instruction\n");
1663 goto bad;
1664 }
1665 break;
1666 default:goto bad;
1667 }
1668 break;
1669
1670 default:goto bad;
1671 }
1672
1673
1674 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
1675 #include "cpu_dyntrans.c"
1676 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
1677 }
1678

  ViewVC Help
Powered by ViewVC 1.1.26