📄 em86real.s
字号:
#define CL 4#define CX 4#define ECX 4#define DX 8#define EDX 8#define BX 12#define EBX 12#define SP 16#define ESP 16#define BP 20#define EBP 20#define SI 24#define ESI 24#define DI 28#define EDI 28/* than the rest of the machine state, big endian !offset name 32 essel segment register selectors (values) 36 cssel 40 sssel 44 dssel 48 fssel 52 gssel 56 eipimg true eip (register named eip is csbase+eip) 60 eflags eip and eflags only valid when C code running ! 64 esbase segment registers bases 68 csbase 72 ssbase 76 dsbase 80 fsbase 84 gsbase 88 iobase For I/O instructions, I/O space virtual base 92 ioperm I/O permission bitmap pointer 96 reason Reason code when calling external emulator 100 nexteip eip past instruction for external emulator 104 parm1 parameter for external emulator 108 parm2 parameter for external emulator 112 _opcode current opcode register for external emulator 116 _base segment register base for external emulator 120 _offset intruction operand offset More internal state was dumped here for debugging in first versions 128 vbase where the 1Mb memory is mapped 132 cntimg instruction counter 136 scratch 192 eipstat array of 32k unsigned long pairs for eip stats*/#define essel 32#define cssel 36#define sssel 40#define dssel 44#define fssel 48#define gssel 52#define eipimg 56#define eflags 60#define esbase 64#define csbase 68#define ssbase 72#define dsbase 76#define fsbase 80#define gsbase 84#define iobase 88#define ioperm 92#define reason 96#define nexteip 100#define parm1 104#define parm2 108#define _opcode 112#define _base 116#define _offset 120#define vbase 128#define cntimg 132#ifdef EIP_STATS#define eipstat 192#endif/* Global registers *//* Some segment register bases are permanently kept in registers since they are often used: these are csb, esb and ssb because they arerequired for jumps, string instructions, and pushes/pops/calls/rets.dsbase is not kept in a register but loaded from memory to allow somewhatmore parallelism in the main emulation loop. */#define one 30 /* Constant one, so pervasive */#define ssb 29#define csb 28#define esb 27#define eip 26 /* That one is indeed csbase+(e)ip-1 */ #define result 25 /* For the use of result, op1, op2 */#define op1 24 /* see the section on flag emulation */#define op2 23#define opbase 22 /* default opcode table */#define flags 21 /* See earlier description */#define opcode 20 /* Opcode */#define opreg 19 /* Opcode extension/register number *//* base is reloaded with the base of the ds segment at the beginning ofevery instruction, it is modified by segment override prefixes, whenthe default base segment is ss, or when the modrm byte specifies aregister operand */#define base 18 /* Instruction's operand segment base */#define offset 17 /* Instruction's memory operand offset *//* used to address a table telling how to decode the addressing modespecified by the modrm byte */#define adbase 16 /* addressing mode table *//* Following registers are used only as dedicated temporaries during decoding,they are free for use during emulation *//* * ceip (current eip) is only in use when we call the external emulator for * instructions that fault. Note that it is forbidden to change flags before * the check for the fault happens (divide by zero...) ! ceip is also used * when measuring timing. */#define ceip 15/* A register used to measure timing information (when enabled) */#ifdef EIP_STATS#define tstamp 14#endif#define count 12 /* Instruction counter. */#define r0 0#define r1 1 /* PPC Stack pointer. */#define r3 3#define r4 4#define r5 5#define r6 6#define r7 7/* Macros to read code stream */#define NEXTBYTE(dest) lbzu dest,1(eip)#define NEXTWORD(dest) lhbrx dest,eip,one; la eip,2(eip)#define NEXTDWORD(dest) lwbrx dest,eip,one; la eip,4(eip)#define NEXT b nop#define GOTNEXT b gotopcode#ifdef __BOOT__ START_GOT GOT_ENTRY(_jtables) GOT_ENTRY(jtab_www) GOT_ENTRY(adtable) END_GOT#else .text#endif .align 2 .global em86_enter .type em86_enter,@functionem86_enter: stwu r1,-96(r1) # allocate stack mflr r0 stmw 14,24(r1) mfcr r4 stw r0,100(r1) mr state,r3 stw r4,20(r1)#ifdef __BOOT__/* We need this since r30 is the default GOT pointer */#define r30 30 GET_GOT/* The relocation of these tables is explicit, this could be done * automatically with fixups but would add more than 8kb in the fixup tables. */ lwz r3,GOT(_jtables) lwz r4,_endjtables-_jtables(r3) sub. r4,r3,r4 beq+ 1f li r0,((_endjtables-_jtables)>>2)+1 addi r3,r3,-4 mtctr r00: lwzu r5,4(r3) add r5,r5,r4 stw r5,0(r3) bdnz 0b1: lwz adbase,GOT(adtable) lwz opbase,GOT(jtab_www)/* Now r30 is only used as constant 1 */#undef r30 li one,1 # pervasive constant#else lis opbase,jtab_www@ha lis adbase,adtable@ha li one,1 # pervasive constant addi opbase,opbase,jtab_www@l addi adbase,adbase,adtable@l#ifdef EIP_STATS li ceip,0 mftb tstamp#endif#endif/* We branch back here when calling an external function tells us to resume */restart: lwz r3,eflags(state) lis flags,(OF_EXPLICIT|ZF_IN_CR|ZF_PROTECT|SF_IN_CR)>>16 lwz csb,csbase(state) extsb result,r3 # SF/PF rlwinm op1,r3,31,0x08 # AF lwz eip,eipimg(state) ZF862ZF(r3) # cr6 addi op2,op1,0 # AF lwz ssb,ssbase(state) rlwimi flags,r3,15,OF_VALUE # OF rlwimi r3,r3,32+RF86-RF,RF,RF # RF lwz esb,esbase(state) ori result,result,0xfb # PF mtcrf 0x06,r3 # RF/DF/IF/TF/SF/ZF lbzux opcode,eip,csb rlwimi flags,r3,27,CF_VALUE # CF xori result,result,0xff # PF lwz count,cntimg(state) GOTNEXT # start the emulator/* Now return */exit: lwz r0,100(r1) lwz r4,20(r1) mtlr r0 lmw 14,24(r1) mtcr r4 addi r1,r1,96 blr trap: crmove 0,RF crclr RF bt- 0,resume sub ceip,eip,csb li r3,code_trapcomplex: addi eip,eip,1 stw r3,reason(state) sub eip,eip,csb stw op1,240(state) stw op2,244(state) stw result,248(state) stw flags,252(state) stw r4,parm1(state) stw r5,parm2(state) stw opcode,_opcode(state) bl _eval_flags stw base,_base(state) stw eip,nexteip(state) stw r3,eflags(state) mr r3,state stw offset,_offset(state) stw ceip,eipimg(state) stw count,cntimg(state) bl em86_trap cmpwi r3,0 bne exit b restart /* Main loop *//* * The two LSB of each entry in the main table mean the following: * 00: indirect opcode: modrm follows and the three middle bits are an * opcode extension. The entry points to another jump table. * 01: direct instruction, branch directly to the routine. * 10: modrm specifies byte size memory and register operands. * 11: modrm specifies word/long memory and register operands. * * The modrm byte, if present, is always loaded in r7. * * Note: most "mr x,y" instructions have been replaced by "addi x,y,0" since * the latter can be executed in the second integer unit on 603e. *//* * This code is very good example of absolutely unmaintainable code. * It was actually much easier to write than it is to understand ! * If my computations are right, the maximum path length from fetching * the opcode to exiting to the actual instruction execution is * 46 instructions (for non-prefixed, single byte opcode instructions). * */ .align 5 #ifdef EIP_STATSnop: NEXTBYTE(opcode)gotopcode: slwi r3,opcode,2 bt- TF,trapresume: lwzx r4,opbase,r3 addi r5,state,eipstat+4 clrlslwi r6,ceip,17,3 mtctr r4 lwzux r7,r5,r6 slwi. r0,r4,30 # two lsb of table entry sub r7,r7,tstamp lwz r6,-4(r5) mftb tstamp addi r6,r6,1 sub ceip,eip,csb stw r6,-4(r5) add r7,r7,tstamp lwz base,dsbase(state) stw r7,0(r5)#elsenop: NEXTBYTE(opcode)gotopcode: slwi r3,opcode,2 bt- TF,trapresume: lwzx r4,opbase,r3 sub ceip,eip,csb mtctr r4 slwi. r0,r4,30 # two lsb of table entry lwz base,dsbase(state) addi count,count,1#endif bgtctr- # for instructions without modrm/* modrm byte present */ NEXTBYTE(r7) # modrm byte cmplwi cr1,r7,192 rlwinm opreg,r7,31,0x1c beq- cr0,8f # extended opcode/* modrm with middle 3 bits specifying a register (non prefixed) */ rlwinm r0,r4,3,0x8 li r4,0x1c0d rlwimi opreg,r7,27,0x01 srw r4,r4,r0 and opreg,opreg,r4 blt cr1,9f/* modrm with 2 register operands */1: rlwinm offset,r7,2,0x1c addi base,state,0 rlwimi offset,r7,30,0x01 and offset,offset,r4 bctr/* Prefixes: first segment overrides */ .align 4_es: NEXTBYTE(r7); addi base,esb,0 oris opcode,opcode,0x8000; b 2f_cs: NEXTBYTE(r7); addi base,csb,0 oris opcode,opcode,0x8000; b 2f_fs: NEXTBYTE(r7); lwz base,fsbase(state) oris opcode,opcode,0x8000; b 2f_gs: NEXTBYTE(r7); lwz base,gsbase(state) oris opcode,opcode,0x8000; b 2f_ss: NEXTBYTE(r7); addi base,ssb,0 oris opcode,opcode,0x8000; b 2f_ds: NEXTBYTE(r7) oris opcode,opcode,0x8000; b 2f/* Lock (unimplemented) and repeat prefixes */_lock: li r3,code_lock; b complex_repnz: NEXTBYTE(r7); rlwimi opcode,one,12,0x1800; b 2f _repz: NEXTBYTE(r7); rlwimi opcode,one,11,0x1800; b 2f /* Operand and address size prefixes */ .align 4_opsize: NEXTBYTE(r7); ori opcode,opcode,0x200 rlwinm r3,opcode,2,0x1ffc; b 2f_adsize: NEXTBYTE(r7); ori opcode,opcode,0x400 rlwinm r3,opcode,2,0x1ffc; b 2f_twobytes: NEXTBYTE(r7); addi r3,r3,0x4002: rlwimi r3,r7,2,0x3fc lwzx r4,opbase,r3 rlwimi opcode,r7,0,0xff mtctr r4 slwi. r0,r4,30 bgtctr- # direct instruction/* modrm byte in a prefixed instruction */ NEXTBYTE(r7) # modrm byte cmpwi cr1,r7,192 rlwinm opreg,r7,31,0x1c beq- 6f /* modrm with middle 3 bits specifying a register (prefixed) */ rlwinm r0,r4,3,0x8 li r4,0x1c0d rlwimi opreg,r7,27,0x01 srw r4,r4,r0 and opreg,opreg,r4 bnl cr1,1b # 2 register operands/* modrm specifying memory with prefix */3: rlwinm r3,r3,27,0xff80 rlwimi adbase,r7,2,0x1c extsh r3,r3 rlwimi r3,r7,31,0x60 lwzx r4,r3,adbase cmpwi cr1,r4,0x3090 bnl+ cr1,10f /* displacement only addressing modes */4: cmpwi r4,0x2000 bne 5f NEXTWORD(offset) bctr5: NEXTDWORD(offset) bctr/* modrm with opcode extension (prefixed) */ 6: lwzx r4,r4,opreg mtctr r4 blt cr1,3b/* modrm with opcode extension and register operand */7: rlwinm offset,r7,2,0x1c addi base,state,0 rlwinm r0,r4,3,0x8 li r4,0x1c0d rlwimi offset,r7,30,0x01 srw r4,r4,r0 and offset,offset,r4 bctr/* modrm with opcode extension (non prefixed) */8: lwzx r4,r4,opreg mtctr r4/* FIXME ? We continue fetching even if the opcode extension is undefined. * It shouldn't do any harm on real mode emulation anyway, and for ROM * BIOS emulation, we are supposed to read valid code. */ bnl cr1,7b/* modrm specifying memory without prefix */9: rlwimi adbase,r7,2,0x1c # memory addressing mode computation rlwinm r3,r7,31,0x60 lwzx r4,r3,adbase cmplwi cr1,r4,0x3090 blt- cr1,4b # displacement only addressing mode10: rlwinm. r0,r7,24,0,1 # three cases distinguished beq- cr1,15f # an sib follows rlwinm r3,r4,30,0x1c # 16bit/32bit/%si index/%di index cmpwi cr1,r3,8 # set cr1 as early as possible rlwinm r6,r4,26,0x1c # base register lwbrx offset,state,r6 # load the base register beq cr0,14f # no displacement cmpw cr2,r4,opcode # check for ss as default base bgt cr0,12f # byte offset beq cr1,11f # 32 bit displacement NEXTWORD(r5) # 16 bit displacement bgt cr1,13f # d16(base,index)/* d16(base) */ add offset,offset,r5 clrlwi offset,offset,16 bgtctr cr2 addi base,ssb,0 bctr/* d32(base) */11: NEXTDWORD(r5) add offset,offset,r5 bgtctr cr2 addi base,ssb,0 bctr/* 8 bit displacement */ 12: NEXTBYTE(r5) extsb r5,r5 bgt cr1,13f/* d8(base) */ extsb r6,r4 add offset,offset,r5 ori r6,r6,0xffff and offset,offset,r6 bgtctr cr2 addi base,ssb,0 bctr/* d8(base,index) and d16(base,index) share this code ! */13: lhbrx r3,state,r3 add offset,offset,r5 add offset,offset,r3 clrlwi offset,offset,16 bgtctr cr2 addi base,ssb,0 bctr/* no displacement: only indexed modes may use ss as default base */ 14: beqctr cr1 # 32 bit register indirect clrlwi offset,offset,16 bltctr cr1 # 16 bit register indirect/* (base,index) */ lhbrx r3,state,r3 # 16 bit [{bp,bx}+{si,di}] cmpw cr2,r4,opcode # check for ss as default base add offset,offset,r3 clrlwi offset,offset,r3 bgtctr+ cr2 addi base,ssb,0 bctr/* sib modes, note that the size of the offset can be known from cr0 */15: NEXTBYTE(r7) # get sib rlwinm r3,r7,31,0x1c # index rlwinm offset,r7,2,0x1c # base cmpwi cr1,r3,ESP # has index ? bne cr0,18f # base+d8/d32 cmpwi offset,EBP beq 17f # d32(,index,scale) xori r4,one,0xcc01 # build 0x0000cc00 rlwnm r4,r4,offset,0,1 # 0 or 0xc0000000 lwbrx offset,state,offset cmpw cr2,r4,opcode # use ss ? beq- cr1,16f # no index/* (base,index,scale) */ lwbrx r3,state,r3 srwi r6,r7,6 slw r3,r3,r6 add offset,offset,r3 bgtctr cr2 addi base,ssb,0 bctr/* (base), in practice only (%esp) is coded this way */16: bgtctr cr2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -