| /* |
| SPARC micro operations |
| |
| Copyright (C) 2003 Thomas M. Ogrisegg <[email protected]> |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "exec.h" |
| |
| /*XXX*/ |
| #define REGNAME g0 |
| #define REG (env->gregs[0]) |
| #include "op_template.h" |
| #define REGNAME g1 |
| #define REG (env->gregs[1]) |
| #include "op_template.h" |
| #define REGNAME g2 |
| #define REG (env->gregs[2]) |
| #include "op_template.h" |
| #define REGNAME g3 |
| #define REG (env->gregs[3]) |
| #include "op_template.h" |
| #define REGNAME g4 |
| #define REG (env->gregs[4]) |
| #include "op_template.h" |
| #define REGNAME g5 |
| #define REG (env->gregs[5]) |
| #include "op_template.h" |
| #define REGNAME g6 |
| #define REG (env->gregs[6]) |
| #include "op_template.h" |
| #define REGNAME g7 |
| #define REG (env->gregs[7]) |
| #include "op_template.h" |
| #define REGNAME i0 |
| #define REG (env->regwptr[16]) |
| #include "op_template.h" |
| #define REGNAME i1 |
| #define REG (env->regwptr[17]) |
| #include "op_template.h" |
| #define REGNAME i2 |
| #define REG (env->regwptr[18]) |
| #include "op_template.h" |
| #define REGNAME i3 |
| #define REG (env->regwptr[19]) |
| #include "op_template.h" |
| #define REGNAME i4 |
| #define REG (env->regwptr[20]) |
| #include "op_template.h" |
| #define REGNAME i5 |
| #define REG (env->regwptr[21]) |
| #include "op_template.h" |
| #define REGNAME i6 |
| #define REG (env->regwptr[22]) |
| #include "op_template.h" |
| #define REGNAME i7 |
| #define REG (env->regwptr[23]) |
| #include "op_template.h" |
| #define REGNAME l0 |
| #define REG (env->regwptr[8]) |
| #include "op_template.h" |
| #define REGNAME l1 |
| #define REG (env->regwptr[9]) |
| #include "op_template.h" |
| #define REGNAME l2 |
| #define REG (env->regwptr[10]) |
| #include "op_template.h" |
| #define REGNAME l3 |
| #define REG (env->regwptr[11]) |
| #include "op_template.h" |
| #define REGNAME l4 |
| #define REG (env->regwptr[12]) |
| #include "op_template.h" |
| #define REGNAME l5 |
| #define REG (env->regwptr[13]) |
| #include "op_template.h" |
| #define REGNAME l6 |
| #define REG (env->regwptr[14]) |
| #include "op_template.h" |
| #define REGNAME l7 |
| #define REG (env->regwptr[15]) |
| #include "op_template.h" |
| #define REGNAME o0 |
| #define REG (env->regwptr[0]) |
| #include "op_template.h" |
| #define REGNAME o1 |
| #define REG (env->regwptr[1]) |
| #include "op_template.h" |
| #define REGNAME o2 |
| #define REG (env->regwptr[2]) |
| #include "op_template.h" |
| #define REGNAME o3 |
| #define REG (env->regwptr[3]) |
| #include "op_template.h" |
| #define REGNAME o4 |
| #define REG (env->regwptr[4]) |
| #include "op_template.h" |
| #define REGNAME o5 |
| #define REG (env->regwptr[5]) |
| #include "op_template.h" |
| #define REGNAME o6 |
| #define REG (env->regwptr[6]) |
| #include "op_template.h" |
| #define REGNAME o7 |
| #define REG (env->regwptr[7]) |
| #include "op_template.h" |
| |
| #define EIP (env->pc) |
| |
| void OPPROTO op_movl_T0_0(void) |
| { |
| T0 = 0; |
| } |
| |
| void OPPROTO op_movl_T0_1(void) |
| { |
| T0 = 1; |
| } |
| |
| void OPPROTO op_movl_T0_im(void) |
| { |
| T0 = PARAM1; |
| } |
| |
| void OPPROTO op_movl_T1_im(void) |
| { |
| T1 = PARAM1; |
| } |
| |
| void OPPROTO op_movl_T2_im(void) |
| { |
| T2 = PARAM1; |
| } |
| |
| void OPPROTO op_addl_T1_im(void) |
| { |
| T1 += PARAM1; |
| } |
| |
| void OPPROTO op_addl_T1_T2(void) |
| { |
| T1 += T2; |
| } |
| |
| void OPPROTO op_subl_T1_T2(void) |
| { |
| T1 -= T2; |
| } |
| |
| void OPPROTO op_add_T1_T0 (void) |
| { |
| T0 += T1; |
| } |
| |
| void OPPROTO op_and_T1_T0 (void) |
| { |
| T0 &= T1; |
| } |
| |
| void OPPROTO op_or_T1_T0 (void) |
| { |
| T0 |= T1; |
| } |
| |
| void OPPROTO op_xor_T1_T0 (void) |
| { |
| T0 ^= T1; |
| } |
| |
| void OPPROTO op_sub_T1_T0 (void) |
| { |
| T0 -= T1; |
| } |
| |
| void OPPROTO op_andn_T1_T0 (void) |
| { |
| T0 &= ~T1; |
| } |
| |
| void OPPROTO op_orn_T1_T0 (void) |
| { |
| T0 |= ~T1; |
| } |
| |
| void OPPROTO op_xnor_T1_T0 (void) |
| { |
| T0 ^= ~T1; |
| } |
| |
| void OPPROTO op_addx_T1_T0 (void) |
| { |
| T0 += T1+((env->psr & PSR_CARRY)?1:0); |
| } |
| |
| void OPPROTO op_umul_T1_T0 (void) |
| { |
| unsigned long long res = T0*T1; |
| T0 = res & 0xffffffff; |
| env->y = res >> 32; |
| } |
| |
| void OPPROTO op_smul_T1_T0 (void) |
| { |
| long long res = T0*T1; |
| T0 = res & 0xffffffff; |
| env->y = res >> 32; |
| } |
| |
| void OPPROTO op_udiv_T1_T0 (void) |
| { |
| unsigned long long x0 = T0 * env->y; |
| unsigned int x1 = T1; |
| T0 = x0 / x1; |
| } |
| |
| void OPPROTO op_sdiv_T1_T0 (void) |
| { |
| long long x0 = T0 * env->y; |
| int x1 = T1; |
| T0 = x0 / x1; |
| } |
| |
| void OPPROTO op_subx_T1_T0 (void) |
| { |
| T0 -= T1+((env->psr & PSR_CARRY)?1:0); |
| } |
| |
| void OPPROTO op_set_flags (void) |
| { |
| env->psr = 0; |
| if (!T0) env->psr |= PSR_ZERO; |
| if ((unsigned int) T0 < (unsigned int) T1) env->psr |= PSR_CARRY; |
| if ((int) T0 < (int) T1) env->psr |= PSR_OVF; |
| if ((int) T0 < 0) env->psr |= PSR_NEG; |
| } |
| |
| void OPPROTO op_sll (void) |
| { |
| T0 <<= T1; |
| } |
| |
| void OPPROTO op_srl (void) |
| { |
| T0 >>= T1; |
| } |
| |
| void OPPROTO op_sra (void) |
| { |
| int x = T0 >> T1; |
| T0 = x; |
| } |
| |
| void OPPROTO op_st (void) |
| { |
| stl ((void *) T0, T1); |
| } |
| |
| void OPPROTO op_stb (void) |
| { |
| stb ((void *) T0, T1); |
| } |
| |
| void OPPROTO op_sth (void) |
| { |
| stw ((void *) T0, T1); |
| } |
| |
| void OPPROTO op_ld (void) |
| { |
| T1 = ldl ((void *) T0); |
| } |
| |
| void OPPROTO op_ldub (void) |
| { |
| T1 = ldub ((void *) T0); |
| } |
| |
| void OPPROTO op_lduh (void) |
| { |
| T1 = lduw ((void *) T0); |
| } |
| |
| void OPPROTO op_ldsb (void) |
| { |
| T1 = ldsb ((void *) T0); |
| } |
| |
| void OPPROTO op_ldsh (void) |
| { |
| T1 = ldsw ((void *) T0); |
| } |
| |
| void OPPROTO op_ldstub (void) |
| { |
| T1 = ldub ((void *) T0); |
| stb ((void *) T0, 0xff); /* XXX: Should be Atomically */ |
| } |
| |
| void OPPROTO op_swap (void) |
| { |
| unsigned int tmp = ldl ((void *) T0); |
| stl ((void *) T0, T1); /* XXX: Should be Atomically */ |
| T1 = tmp; |
| } |
| |
| void OPPROTO op_ldd (void) |
| { |
| T1 = ldl ((void *) T0); |
| T0 = ldl ((void *) T0+4); |
| } |
| |
| void OPPROTO op_wry (void) |
| { |
| env->y = T0^T1; |
| } |
| |
| void OPPROTO op_rdy (void) |
| { |
| T0 = env->y; |
| } |
| |
| #define regwptr (env->regwptr) |
| |
| void OPPROTO op_save (void) |
| { |
| regwptr -= 16; |
| } |
| |
| void OPPROTO op_restore (void) |
| { |
| regwptr += 16; |
| } |
| |
| void OPPROTO op_trap (void) |
| { |
| env->exception_index = PARAM1; |
| cpu_loop_exit (); |
| } |
| |
| void OPPROTO op_exit_tb (void) |
| { |
| EXIT_TB (); |
| } |
| |
| void OPPROTO op_eval_be (void) |
| { |
| T0 = (env->psr & PSR_ZERO); |
| } |
| |
| #define FLAG_SET(x) (env->psr&x)?1:0 |
| #define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY) |
| |
| void OPPROTO op_eval_ble (void) |
| { |
| GET_FLAGS; |
| T0 = Z | (N^V); |
| } |
| |
| void OPPROTO op_eval_bl (void) |
| { |
| GET_FLAGS; |
| T0 = N^V; |
| } |
| |
| void OPPROTO op_eval_bleu (void) |
| { |
| GET_FLAGS; |
| T0 = C|Z; |
| } |
| |
| void OPPROTO op_eval_bcs (void) |
| { |
| T0 = (env->psr & PSR_CARRY); |
| } |
| |
| void OPPROTO op_eval_bvs (void) |
| { |
| T0 = (env->psr & PSR_OVF); |
| } |
| |
| void OPPROTO op_eval_bneg (void) |
| { |
| T0 = (env->psr & PSR_NEG); |
| } |
| |
| void OPPROTO op_eval_bne (void) |
| { |
| T0 = !(env->psr & PSR_ZERO); |
| } |
| |
| void OPPROTO op_eval_bg (void) |
| { |
| GET_FLAGS; |
| T0 = !(Z | (N^V)); |
| } |
| |
| /*XXX: This seems to be documented wrong in the SPARC V8 Manual |
| The manual states: !(N^V) |
| but I assume Z | !(N^V) to be correct */ |
| void OPPROTO op_eval_bge (void) |
| { |
| GET_FLAGS; |
| T0 = Z | !(N^V); |
| } |
| |
| void OPPROTO op_eval_bgu (void) |
| { |
| GET_FLAGS; |
| T0 = !(C | Z); |
| } |
| |
| void OPPROTO op_eval_bcc (void) |
| { |
| T0 = !(env->psr & PSR_CARRY); |
| } |
| |
| void OPPROTO op_eval_bpos (void) |
| { |
| T0 = !(env->psr & PSR_NEG); |
| } |
| |
| void OPPROTO op_eval_bvc (void) |
| { |
| T0 = !(env->psr & PSR_OVF); |
| } |
| |
| void OPPROTO op_jmp_im (void) |
| { |
| env->pc = PARAM1; |
| } |
| |
| void OPPROTO op_call (void) |
| { |
| regwptr[7] = PARAM1-4; |
| env->pc = PARAM1+PARAM2; |
| } |
| |
| void OPPROTO op_jmpl (void) |
| { |
| env->npc = T0; |
| } |
| |
| void OPPROTO op_generic_jmp_1 (void) |
| { |
| T1 = PARAM1; |
| env->pc = PARAM1+PARAM2; |
| } |
| |
| void OPPROTO op_generic_jmp_2 (void) |
| { |
| T1 = PARAM1; |
| env->pc = env->npc; |
| } |
| |
| unsigned long old_T0; |
| |
| void OPPROTO op_save_T0 (void) |
| { |
| old_T0 = T0; |
| } |
| |
| void OPPROTO op_restore_T0 (void) |
| { |
| T0 = old_T0; |
| } |
| |
| void OPPROTO op_generic_branch (void) |
| { |
| if (T0) |
| JUMP_TB (__func__, PARAM1, 0, PARAM2); |
| else |
| JUMP_TB (__func__, PARAM1, 1, PARAM3); |
| FORCE_RET (); |
| } |
| |
| void OPPROTO op_generic_branch_a (void) |
| { |
| if (T0) |
| env->npc = PARAM3; |
| else |
| JUMP_TB (__func__, PARAM1, 0, PARAM2); |
| FORCE_RET (); |
| } |
| |
| void OPPROTO op_noop (void) |
| { |
| } |