X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=cyclone68000.git;a=blobdiff_plain;f=Cyclone%2FOpLogic.cpp;h=d4d9b13cce106a7d0a6cde90cafdb0819527087f;hp=c9c724b66703f13feb56a212c42c647ac0fa93d0;hb=d9d77995ec88700f438b3638df179a014bf4f6b3;hpb=7441f043a0ba83bd919db25bf3b8e35ae635012a diff --git a/Cyclone/OpLogic.cpp b/Cyclone/OpLogic.cpp index c9c724b..d4d9b13 100644 --- a/Cyclone/OpLogic.cpp +++ b/Cyclone/OpLogic.cpp @@ -1,24 +1,26 @@ // This file is part of the Cyclone 68000 Emulator -// Copyright (c) 2011 FinalDave (emudave (at) gmail.com) +// Copyright (c) 2004,2011 FinalDave (emudave (at) gmail.com) +// Copyright (c) 2005-2011 Gražvydas "notaz" Ignotas (notasas (at) gmail.com) // This code is licensed under the GNU General Public License version 2.0 and the MAME License. // You can choose the license that has the most advantages for you. // SVN repository can be found at http://code.google.com/p/cyclone68000/ + #include "app.h" // --------------------- Opcodes 0x0100+ --------------------- -// Emit a Btst (Register) opcode 0000nnn1 00aaaaaa +// Emit a Btst (Register) opcode 0000nnn1 ttaaaaaa int OpBtstReg(int op) { int use=0; int type=0,sea=0,tea=0; int size=0; - type=(op>>6)&3; + type=(op>>6)&3; // Btst/Bchg/Bclr/Bset // Get source and target EA sea=(op>>9)&7; tea=op&0x003f; @@ -33,37 +35,43 @@ int OpBtstReg(int op) if (EaCanWrite(tea)==0) return 1; } - use=OpBase(op); + use=OpBase(op,size); use&=~0x0e00; // Use same handler for all registers if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op); Cycles=4; - if (tea<0x10) Cycles+=2; - if (type>0) Cycles+=4; + OpStart(op,tea); - ot(" mov r10,#1\n"); + if(type==1||type==3) { + Cycles=8; + } else { + Cycles=type?8:4; + if(size>=2) Cycles+=2; + } - EaCalc (0,0x0e00,sea,0); - EaRead (0, 0,sea,0); - ot(" bic r9,r9,#0x40000000 ;@ Blank Z flag\n"); - ot(" mov r10,r10,lsl r0 ;@ Make bit mask\n"); + EaCalcReadNoSE(-1,11,sea,0,0x0e00); + + EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f); + + if (tea>=0x10) + ot(" and r11,r11,#7 ;@ mem - do mod 8\n"); // size always 0 + else ot(" and r11,r11,#31 ;@ reg - do mod 32\n"); // size always 2 ot("\n"); - EaCalc(11,0x003f,tea,size); - EaRead(11, 0,tea,size); - ot(" tst r0,r10 ;@ Do arithmetic\n"); - ot(" orreq r9,r9,#0x40000000 ;@ Get Z flag\n"); + ot(" mov r1,#1\n"); + ot(" tst r0,r1,lsl r11 ;@ Do arithmetic\n"); + ot(" bicne r10,r10,#0x40000000\n"); + ot(" orreq r10,r10,#0x40000000 ;@ Get Z flag\n"); ot("\n"); if (type>0) { - if (type==1) ot(" eor r1,r0,r10 ;@ Toggle bit\n"); - if (type==2) ot(" bic r1,r0,r10 ;@ Clear bit\n"); - if (type==3) ot(" orr r1,r0,r10 ;@ Set bit\n"); + if (type==1) ot(" eor r1,r0,r1,lsl r11 ;@ Toggle bit\n"); + if (type==2) ot(" bic r1,r0,r1,lsl r11 ;@ Clear bit\n"); + if (type==3) ot(" orr r1,r0,r1,lsl r11 ;@ Set bit\n"); ot("\n"); - EaWrite(11, 1,tea,size); + EaWrite(8,1,tea,size,0x003f,0,0); } - OpEnd(); + OpEnd(tea); return 0; } @@ -83,43 +91,54 @@ int OpBtstImm(int op) if (tea<0x10) size=2; // For registers, 32-bits // See if we can do this opcode: - if (EaCanRead(tea,0)==0) return 1; + if (EaCanRead(tea,0)==0||EaAn(tea)||tea==0x3c) return 1; if (type>0) { if (EaCanWrite(tea)==0) return 1; } - use=OpBase(op); + use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op); Cycles=4; - if (type<3 && tea<0x10) Cycles+=2; - if (type>0) Cycles+=4; + OpStart(op,sea,tea); - ot(" mov r10,#1\n"); ot("\n"); - EaCalc ( 0,0x0000,sea,0); - EaRead ( 0, 0,sea,0); - ot(" bic r9,r9,#0x40000000 ;@ Blank Z flag\n"); - ot(" mov r10,r10,lsl r0 ;@ Make bit mask\n"); + EaCalcReadNoSE(-1,0,sea,0,0); + ot(" mov r11,#1\n"); + ot(" bic r10,r10,#0x40000000 ;@ Blank Z flag\n"); + if (tea>=0x10) + ot(" and r0,r0,#7 ;@ mem - do mod 8\n"); // size always 0 + else ot(" and r0,r0,#0x1F ;@ reg - do mod 32\n"); // size always 2 + ot(" mov r11,r11,lsl r0 ;@ Make bit mask\n"); ot("\n"); - EaCalc (11,0x003f,tea,size); - EaRead (11, 0,tea,size); - ot(" tst r0,r10 ;@ Do arithmetic\n"); - ot(" orreq r9,r9,#0x40000000 ;@ Get Z flag\n"); + if(type==1||type==3) { + Cycles=12; + } else { + Cycles=type?12:8; + if(size>=2) Cycles+=2; + } + + EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f); + ot(" tst r0,r11 ;@ Do arithmetic\n"); + ot(" orreq r10,r10,#0x40000000 ;@ Get Z flag\n"); ot("\n"); if (type>0) { - if (type==1) ot(" eor r1,r0,r10 ;@ Toggle bit\n"); - if (type==2) ot(" bic r1,r0,r10 ;@ Clear bit\n"); - if (type==3) ot(" orr r1,r0,r10 ;@ Set bit\n"); + if (type==1) ot(" eor r1,r0,r11 ;@ Toggle bit\n"); + if (type==2) ot(" bic r1,r0,r11 ;@ Clear bit\n"); + if (type==3) ot(" orr r1,r0,r11 ;@ Set bit\n"); ot("\n"); - EaWrite(11, 1,tea,size); + EaWrite(8, 1,tea,size,0x003f,0,0); +#if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES + // this is a bit hacky (device handlers might modify cycles) + if (tea==0x38||tea==0x39) + ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); +#endif } - OpEnd(); + OpEnd(sea,tea); return 0; } @@ -134,54 +153,73 @@ int OpNeg(int op) ea =op&0x003f; size=(op>>6)&3; if (size>=3) return 1; - switch (type) - { - case 1: case 2: case 3: break; - default: return 1; // todo - } - // See if we can do this opcode: - if (EaCanRead (ea,size)==0) return 1; + if (EaCanRead (ea,size)==0||EaAn(ea)) return 1; if (EaCanWrite(ea )==0) return 1; - use=OpBase(op); + use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op); Cycles=size<2?4:6; + OpStart(op,ea); Cycles=size<2?4:6; + if(ea >= 0x10) Cycles*=2; - EaCalc (10,0x003f,ea,size); + EaCalc (11,0x003f,ea,size,0,0); - if (type!=1) EaRead (10,0,ea,size); // Don't need to read for 'clr' + if (type!=1) EaRead (11,0,ea,size,0x003f,0,0); // Don't need to read for 'clr' (or do we, for a dummy read?) if (type==1) ot("\n"); + if (type==0) + { + ot(";@ Negx:\n"); + GetXBit(1); + if(size!=2) ot(" mov r0,r0,asl #%i\n",size?16:24); + ot(" rscs r1,r0,#0 ;@ do arithmetic\n"); + ot(" orr r3,r10,#0xb0000000 ;@ for old Z\n"); + OpGetFlags(1,1,0); + if(size!=2) { + ot(" movs r1,r1,asr #%i\n",size?16:24); + ot(" orreq r10,r10,#0x40000000 ;@ possily missed Z\n"); + } + ot(" andeq r10,r10,r3 ;@ fix Z\n"); + ot("\n"); + } + if (type==1) { ot(";@ Clear:\n"); ot(" mov r1,#0\n"); - ot(" mov r9,#0x40000000 ;@ NZCV=0100\n"); + ot(" mov r10,#0x40000000 ;@ NZCV=0100\n"); ot("\n"); } if (type==2) { ot(";@ Neg:\n"); + if(size!=2) ot(" mov r0,r0,asl #%i\n",size?16:24); ot(" rsbs r1,r0,#0\n"); OpGetFlags(1,1); + if(size!=2) ot(" mov r1,r1,asr #%i\n",size?16:24); ot("\n"); } if (type==3) { ot(";@ Not:\n"); - ot(" mvn r1,r0\n"); + if(size!=2) { + ot(" mov r0,r0,asl #%i\n",size?16:24); + ot(" mvn r1,r0,asr #%i\n",size?16:24); + } + else + ot(" mvn r1,r0\n"); ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); OpGetFlags(0,0); ot("\n"); } - EaWrite(10, 1,ea,size); + if (type==1) eawrite_check_addrerr=1; + EaWrite(11, 1,ea,size,0x003f,0,0); - OpEnd(); + OpEnd(ea); return 0; } @@ -199,14 +237,14 @@ int OpSwap(int op) OpStart(op); Cycles=4; - EaCalc (10,0x0007,ea,2); - EaRead (10, 0,ea,2); + EaCalc (11,0x0007,ea,2,1); + EaRead (11, 0,ea,2,0x0007,1); ot(" mov r1,r0,ror #16\n"); ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); OpGetFlags(0,0); - EaWrite(10, 1,8,2); + EaWrite(11, 1,8,2,0x0007,1); OpEnd(); @@ -224,21 +262,21 @@ int OpTst(int op) size=(op>>6)&3; if (size>=3) return 1; // See if we can do this opcode: - if (EaCanWrite(sea)==0) return 1; + if (EaCanWrite(sea)==0||EaAn(sea)) return 1; - use=OpBase(op); + use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op); Cycles=4; + OpStart(op,sea); Cycles=4; - EaCalc ( 0,0x003f,sea,size); - EaRead ( 0, 0,sea,size); + EaCalc ( 0,0x003f,sea,size,1); + EaRead ( 0, 0,sea,size,0x003f,1); ot(" adds r0,r0,#0 ;@ Defines NZ, clears CV\n"); - ot(" mrs r9,cpsr ;@ r9=flags\n"); + ot(" mrs r10,cpsr ;@ r10=flags\n"); ot("\n"); - OpEnd(); + OpEnd(sea); return 0; } @@ -254,21 +292,21 @@ int OpExt(int op) size=(op>>6)&1; shift=32-(8<=2; + OpStart(op,ea,0,changed_cycles); Cycles=8; + if (ea<8) Cycles=4; - ot(" mov r1,#0\n"); + if (cc) + ot(" mov r1,#0\n"); - if (cc!=1) + switch (cc) { - ot(";@ Is the condition true?\n"); - if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n"); - ot(" msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n"); - if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n"); - ot(" mvn%s r1,r1\n",cond[cc]); + case 0: // T + ot(" mvn r1,#0\n"); + if (ea<8) Cycles+=2; + break; + case 1: // F + break; + case 2: // hi + ot(" tst r10,#0x60000000 ;@ hi: !C && !Z\n"); + ot(" mvneq r1,r1\n"); + if (ea<8) ot(" subeq r5,r5,#2 ;@ Extra cycles\n"); + break; + case 3: // ls + ot(" tst r10,#0x60000000 ;@ ls: C || Z\n"); + ot(" mvnne r1,r1\n"); + if (ea<8) ot(" subne r5,r5,#2 ;@ Extra cycles\n"); + break; + default: + ot(";@ Is the condition true?\n"); + ot(" msr cpsr_flg,r10 ;@ ARM flags = 68000 flags\n"); + ot(" mvn%s r1,r1\n",cond[cc]); + if (ea<8) ot(" sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]); + break; } - if (ea<0x10) ot(" sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]); ot("\n"); - EaCalc (0,0x003f, ea,size); - EaWrite(0, 1, ea,size); + eawrite_check_addrerr=1; + EaCalc (0,0x003f, ea,size,0,0); + EaWrite(0, 1, ea,size,0x003f,0,0); - OpEnd(); + opend_op_changes_cycles=changed_cycles; + OpEnd(ea,0); return 0; } // Emit a Asr/Lsr/Roxr/Ror opcode static int EmitAsr(int op,int type,int dir,int count,int size,int usereg) { - char pct[8]=""; + char pct[8]=""; // count int shift=32-(8<=1) sprintf(pct,"#%d",count); // Fixed count - if (count<0) - { - ot(" mov r2,r8,lsr #9 ;@ Get 'n'\n"); - ot(" and r2,r2,#7\n\n"); strcpy(pct,"r2"); - } - if (usereg) { ot(";@ Use Dn for count:\n"); - ot(" ldr r2,[r7,r2,lsl #2]\n"); + ot(" and r2,r8,#0x0e00\n"); + ot(" ldr r2,[r7,r2,lsr #7]\n"); ot(" and r2,r2,#63\n"); ot("\n"); + strcpy(pct,"r2"); + } + else if (count<0) + { + ot(" mov r2,r8,lsr #9 ;@ Get 'n'\n"); + ot(" and r2,r2,#7\n\n"); strcpy(pct,"r2"); } // Take 2*n cycles: @@ -353,22 +411,45 @@ static int EmitAsr(int op,int type,int dir,int count,int size,int usereg) // Asr/Lsr if (dir==0 && size<2) { - ot(";@ For shift right, also copy to lowest bits (to get carry bit):\n"); - ot(" orr r0,r0,r0,lsr #%d\n",32-(8<>9)&7; dir =(op>>8)&1; size =(op>>6)&3; - if (size>=3) return 1; // todo Asr EA + if (size>=3) return 1; // use OpAsrEa() usereg=(op>>5)&1; type =(op>>3)&3; @@ -480,27 +612,28 @@ int OpAsr(int op) // Use the same opcode for target registers: use=op&~0x0007; - // As long as count is not 8, use the same opcode for all shift counts:: - if (usereg==0 && count!=8) { use|=0x0e00; count=-1; } + // As long as count is not 8, use the same opcode for all shift counts: + if (usereg==0 && count!=8 && !(count==1&&type==2)) { use|=0x0e00; count=-1; } if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op); Cycles=size<2?6:8; + OpStart(op,ea,0,count<0); Cycles=size<2?6:8; - EaCalc(10,0x0007, ea,size); - EaRead(10, 0, ea,size,1); + EaCalc(11,0x0007, ea,size,1); + EaRead(11, 0, ea,size,0x0007,1); EmitAsr(op,type,dir,count, size,usereg); - EaWrite(10, 0, ea,size,1); + EaWrite(11, 0, ea,size,0x0007,1); - OpEnd(); + opend_op_changes_cycles = (count<0); + OpEnd(ea,0); return 0; } -// Asr/l/Ror/l etc EA - 11100ttd 11eeeeee +// Asr/Lsr/Roxr/Ror etc EA - 11100ttd 11eeeeee int OpAsrEa(int op) { int use=0,type=0,dir=0,ea=0,size=1; @@ -514,20 +647,68 @@ int OpAsrEa(int op) if (EaCanRead(ea,0)==0) return 1; if (EaCanWrite(ea)==0) return 1; - use=OpBase(op); + use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op); Cycles=8; + OpStart(op,ea); Cycles=6; // EmitAsr() will add 2 - EaCalc (10,0x003f,ea,size); - EaRead (10, 0,ea,size,1); + EaCalc (11,0x003f,ea,size,1); + EaRead (11, 0,ea,size,0x003f,1); - EmitAsr(op,type,dir,1, size,0); + EmitAsr(op,type,dir,1,size,0); - ot(";@ Save shifted value back to EA:\n"); - ot(" mov r1,r0\n"); - EaWrite(10, 1,ea,size,1); + EaWrite(11, 0,ea,size,0x003f,1); - OpEnd(); + OpEnd(ea); return 0; } + +int OpTas(int op, int gen_special) +{ + int ea=0; + int use=0; + + ea=op&0x003f; + + // See if we can do this opcode: + if (EaCanWrite(ea)==0 || EaAn(ea)) return 1; + + use=OpBase(op,0); + if (op!=use) { OpUse(op,use); return 0; } // Use existing handler + + if (!gen_special) OpStart(op,ea); + else + ot("Op%.4x_%s\n", op, ms?"":":"); + + Cycles=4; + if(ea>=8) Cycles+=10; + + EaCalc (11,0x003f,ea,0,1); + EaRead (11, 1,ea,0,0x003f,1); + + ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); + OpGetFlags(0,0); + ot("\n"); + +#if CYCLONE_FOR_GENESIS + // the original Sega hardware ignores write-back phase (to memory only) + if (ea < 0x10 || gen_special) { +#endif + ot(" orr r1,r1,#0x80000000 ;@ set bit7\n"); + + EaWrite(11, 1,ea,0,0x003f,1); +#if CYCLONE_FOR_GENESIS + } +#endif + + OpEnd(ea); + +#if (CYCLONE_FOR_GENESIS == 2) + if (!gen_special && ea >= 0x10) { + OpTas(op, 1); + } +#endif + + return 0; +} +