?? ppc_alu.c
字號(hào):
/* * PearPC * ppc_alu.cc * * Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//*#include "debug/tracers.h"#include "cpu/debug.h"*/#include "debug.h"#include "tracers.h"#include "ppc_alu.h"#include "ppc_dec.h"#include "ppc_exc.h"#include "ppc_cpu.h"#include "ppc_opc.h"#include "ppc_tools.h"static inline uint32 ppc_mask(int MB, int ME){ uint32 mask; if (MB <= ME) { if (ME-MB == 31) { mask = 0xffffffff; } else { mask = ((1<<(ME-MB+1))-1)<<(31-ME); } } else { mask = ppc_word_rotl((1<<(32-MB+ME+1))-1, 31-ME); } return mask;}/* * addx Add * .422 */void ppc_opc_addx(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); gCPU.gpr[rD] = gCPU.gpr[rA] + gCPU.gpr[rB]; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); }}/* * addox Add with Overflow * .422 */void ppc_opc_addox(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); gCPU.gpr[rD] = gCPU.gpr[rA] + gCPU.gpr[rB]; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); } // update XER flags PPC_ALU_ERR("addox unimplemented\n");}/* * addcx Add Carrying * .423 */void ppc_opc_addcx(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); uint32 a = gCPU.gpr[rA]; gCPU.gpr[rD] = a + gCPU.gpr[rB]; // update xer if (gCPU.gpr[rD] < a) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); }}/* * addcox Add Carrying with Overflow * .423 */void ppc_opc_addcox(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); uint32 a = gCPU.gpr[rA]; gCPU.gpr[rD] = a + gCPU.gpr[rB]; // update xer if (gCPU.gpr[rD] < a) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); } // update XER flags PPC_ALU_ERR("addcox unimplemented\n");}/* * addex Add Extended * .424 */void ppc_opc_addex(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); uint32 a = gCPU.gpr[rA]; uint32 b = gCPU.gpr[rB]; uint32 ca = ((gCPU.xer&XER_CA)?1:0); gCPU.gpr[rD] = a + b + ca; // update xer if (ppc_carry_3(a, b, ca)) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); }}/* * addeox Add Extended with Overflow * .424 */void ppc_opc_addeox(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); uint32 a = gCPU.gpr[rA]; uint32 b = gCPU.gpr[rB]; uint32 ca = ((gCPU.xer&XER_CA)?1:0); gCPU.gpr[rD] = a + b + ca; // update xer if (ppc_carry_3(a, b, ca)) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); } // update XER flags PPC_ALU_ERR("addeox unimplemented\n");}/* * addi Add Immediate * .425 */void ppc_opc_addi(){ int rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm); gCPU.gpr[rD] = (rA ? gCPU.gpr[rA] : 0) + imm; //fprintf(stderr, "in %s,rD=0x%x,rA=0x%x,imm=0x%x,gCPU.gpr[rD]=0x%x\n",__FUNCTION__, rD,rA,imm,gCPU.gpr[rD]);}/* * addic Add Immediate Carrying * .426 */void ppc_opc_addic(){ int rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm); uint32 a = gCPU.gpr[rA]; gCPU.gpr[rD] = a + imm; // update XER if (gCPU.gpr[rD] < a) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; }}/* * addic. Add Immediate Carrying and Record * .427 */void ppc_opc_addic_(){ int rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm); uint32 a = gCPU.gpr[rA]; gCPU.gpr[rD] = a + imm; // update XER if (gCPU.gpr[rD] < a) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]);}/* * addis Add Immediate Shifted * .428 */void ppc_opc_addis(){ int rD, rA; uint32 imm; PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rD, rA, imm); gCPU.gpr[rD] = (rA ? gCPU.gpr[rA] : 0) + imm;}/* * addmex Add to Minus One Extended * .429 */void ppc_opc_addmex(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); PPC_OPC_ASSERT(rB == 0); uint32 a = gCPU.gpr[rA]; uint32 ca = ((gCPU.xer&XER_CA)?1:0); gCPU.gpr[rD] = a + ca + 0xffffffff; if (a || ca) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); }}/* * addmeox Add to Minus One Extended with Overflow * .429 */void ppc_opc_addmeox(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); PPC_OPC_ASSERT(rB == 0); uint32 a = gCPU.gpr[rA]; uint32 ca = ((gCPU.xer&XER_CA)?1:0); gCPU.gpr[rD] = a + ca + 0xffffffff; if (a || ca) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); } // update XER flags PPC_ALU_ERR("addmeox unimplemented\n");}/* * addzex Add to Zero Extended * .430 */void ppc_opc_addzex(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); PPC_OPC_ASSERT(rB == 0); uint32 a = gCPU.gpr[rA]; uint32 ca = ((gCPU.xer&XER_CA)?1:0); gCPU.gpr[rD] = a + ca; if ((a == 0xffffffff) && ca) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } // update xer if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); }}/* * addzeox Add to Zero Extended with Overflow * .430 */void ppc_opc_addzeox(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); PPC_OPC_ASSERT(rB == 0); uint32 a = gCPU.gpr[rA]; uint32 ca = ((gCPU.xer&XER_CA)?1:0); gCPU.gpr[rD] = a + ca; if ((a == 0xffffffff) && ca) { gCPU.xer |= XER_CA; } else { gCPU.xer &= ~XER_CA; } // update xer if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); } // update XER flags PPC_ALU_ERR("addzeox unimplemented\n");}/* * andx AND * .431 */void ppc_opc_andx(){ int rS, rA, rB; PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); gCPU.gpr[rA] = gCPU.gpr[rS] & gCPU.gpr[rB]; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rA]); }}/* * andcx AND with Complement * .432 */void ppc_opc_andcx(){ int rS, rA, rB; PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); gCPU.gpr[rA] = gCPU.gpr[rS] & ~gCPU.gpr[rB]; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rA]); }}/* * andi. AND Immediate * .433 */void ppc_opc_andi_(){ int rS, rA; uint32 imm; PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, rS, rA, imm); gCPU.gpr[rA] = gCPU.gpr[rS] & imm; // update cr0 flags ppc_update_cr0(gCPU.gpr[rA]);}/* * andis. AND Immediate Shifted * .434 */void ppc_opc_andis_(){ int rS, rA; uint32 imm; PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rS, rA, imm); gCPU.gpr[rA] = gCPU.gpr[rS] & imm; // update cr0 flags ppc_update_cr0(gCPU.gpr[rA]);}/* * cmp Compare * .442 */static uint32 ppc_cmp_and_mask[8] = { 0xfffffff0, 0xffffff0f, 0xfffff0ff, 0xffff0fff, 0xfff0ffff, 0xff0fffff, 0xf0ffffff, 0x0fffffff,};void ppc_opc_cmp(){ uint32 cr; int rA, rB; PPC_OPC_TEMPL_X(gCPU.current_opc, cr, rA, rB); cr >>= 2; sint32 a = gCPU.gpr[rA]; sint32 b = gCPU.gpr[rB]; uint32 c; if (a < b) { c = 8; } else if (a > b) { c = 4; } else { c = 2; } if (gCPU.xer & XER_SO) c |= 1; cr = 7-cr; gCPU.cr &= ppc_cmp_and_mask[cr]; gCPU.cr |= c<<(cr*4);}/* * cmpi Compare Immediate * .443 */void ppc_opc_cmpi(){ uint32 cr; int rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, cr, rA, imm); cr >>= 2; sint32 a = gCPU.gpr[rA]; sint32 b = imm; uint32 c;/* if (!VALGRIND_CHECK_READABLE(a, sizeof a)) { ht_printf("%08x <--i\n", gCPU.pc);// SINGLESTEP(""); }*/ if (a < b) { c = 8; } else if (a > b) { c = 4; } else { c = 2; } if (gCPU.xer & XER_SO) c |= 1; cr = 7-cr; gCPU.cr &= ppc_cmp_and_mask[cr]; gCPU.cr |= c<<(cr*4); //fprintf(stderr,"in %s,rA=%d,gpr[rA]=0x%d,im=%d,c=%d\n",__FUNCTION__,rA,gCPU.gpr[rA],imm,c);}/* * cmpl Compare Logical * .444 */void ppc_opc_cmpl(){ uint32 cr; int rA, rB; PPC_OPC_TEMPL_X(gCPU.current_opc, cr, rA, rB); cr >>= 2; uint32 a = gCPU.gpr[rA]; uint32 b = gCPU.gpr[rB]; uint32 c; if (a < b) { c = 8; } else if (a > b) { c = 4; } else { c = 2; } if (gCPU.xer & XER_SO) c |= 1; cr = 7-cr; gCPU.cr &= ppc_cmp_and_mask[cr]; gCPU.cr |= c<<(cr*4);}/* * cmpli Compare Logical Immediate * .445 */void ppc_opc_cmpli(){ uint32 cr; int rA; uint32 imm; PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, cr, rA, imm); cr >>= 2; uint32 a = gCPU.gpr[rA]; uint32 b = imm; uint32 c; if (a < b) { c = 8; } else if (a > b) { c = 4; } else { c = 2; } if (gCPU.xer & XER_SO) c |= 1; cr = 7-cr; gCPU.cr &= ppc_cmp_and_mask[cr]; gCPU.cr |= c<<(cr*4);}/* * cntlzwx Count Leading Zeros Word * .447 */void ppc_opc_cntlzwx(){ int rS, rA, rB; PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); PPC_OPC_ASSERT(rB==0); uint32 n=0; uint32 x=0x80000000; uint32 v=gCPU.gpr[rS]; while (!(v & x)) { n++; if (n==32) break; x>>=1; } gCPU.gpr[rA] = n; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rA]); }}/* * crand Condition Register AND * .448 */void ppc_opc_crand(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); if ((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB)))) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * crandc Condition Register AND with Complement * .449 */void ppc_opc_crandc(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); if ((gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB)))) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * creqv Condition Register Equivalent * .450 */void ppc_opc_creqv(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); if (((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB)))) || (!(gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB))))) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * crnand Condition Register NAND * .451 */void ppc_opc_crnand(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); if (!((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB))))) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * crnor Condition Register NOR * .452 */void ppc_opc_crnor(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); uint32 t = (1<<(31-crA)) | (1<<(31-crB)); if (!(gCPU.cr & t)) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * cror Condition Register OR * .453 */void ppc_opc_cror(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); uint32 t = (1<<(31-crA)) | (1<<(31-crB)); if (gCPU.cr & t) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * crorc Condition Register OR with Complement * .454 */void ppc_opc_crorc(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); if ((gCPU.cr & (1<<(31-crA))) || !(gCPU.cr & (1<<(31-crB)))) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * crxor Condition Register XOR * .448 */void ppc_opc_crxor(){ int crD, crA, crB; PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB); if ((!(gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB)))) || ((gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB))))) { gCPU.cr |= (1<<(31-crD)); } else { gCPU.cr &= ~(1<<(31-crD)); }}/* * divwx Divide Word * .470 */void ppc_opc_divwx(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); if (!gCPU.gpr[rB]) { PPC_ALU_WARN("division by zero @%08x\n", gCPU.pc); SINGLESTEP(""); } sint32 a = gCPU.gpr[rA]; sint32 b = gCPU.gpr[rB]; gCPU.gpr[rD] = a / b; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); }}/* * divwox Divide Word with Overflow * .470 */void ppc_opc_divwox(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); if (!gCPU.gpr[rB]) { PPC_ALU_ERR("division by zero\n"); } sint32 a = gCPU.gpr[rA]; sint32 b = gCPU.gpr[rB]; gCPU.gpr[rD] = a / b; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); } // update XER flags PPC_ALU_ERR("divwox unimplemented\n");}/* * divwux Divide Word Unsigned * .472 */void ppc_opc_divwux(){ int rD, rA, rB; PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB); if (!gCPU.gpr[rB]) { PPC_ALU_WARN("division by zero @%08x\n", gCPU.pc); SINGLESTEP(""); } gCPU.gpr[rD] = gCPU.gpr[rA] / gCPU.gpr[rB]; if (gCPU.current_opc & PPC_OPC_Rc) { // update cr0 flags ppc_update_cr0(gCPU.gpr[rD]); }}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -