From: notaz Date: Sat, 14 Jul 2007 22:07:41 +0000 (+0000) Subject: optimizations, bugfixes, uae works (but with timing glitches?) X-Git-Tag: v1.85~702 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee5e024ce624b4a5e5efc38e5d7c6a040a48a8b0;p=picodrive.git optimizations, bugfixes, uae works (but with timing glitches?) git-svn-id: file:///home/notaz/opt/svn/PicoDrive@191 be3aeb3a-fb24-0410-a615-afba39da0efa --- diff --git a/cpu/Cyclone/Cyclone.txt b/cpu/Cyclone/Cyclone.txt index b2c675de..8a68e16e 100644 --- a/cpu/Cyclone/Cyclone.txt +++ b/cpu/Cyclone/Cyclone.txt @@ -45,6 +45,8 @@ v0.0087 notaz + Changed "MOVEA (An)+ An" behaviour. + Fixed flag behaviour of ROXR, ASL, LSR and NBCD in certain situations. Hopefully got them right now. + + Cyclone no longer sets most significant bits while pushing PC to stack. + Amiga Kickstart depends on this. + Additional functionality added for MAME and other ports (see config.h). v0.0086 notaz diff --git a/cpu/Cyclone/Main.cpp b/cpu/Cyclone/Main.cpp index 5647fb1d..5fed8ee1 100644 --- a/cpu/Cyclone/Main.cpp +++ b/cpu/Cyclone/Main.cpp @@ -10,7 +10,7 @@ char *Narm[4]={ "b", "h","",""}; // Normal ARM Extensions for operand sizes 0,1, char *Sarm[4]={"sb","sh","",""}; // Sign-extend ARM Extensions for operand sizes 0,1,2 int Cycles; // Current cycles for opcode int pc_dirty; // something changed PC during processing -static int arm_op_count; +int arm_op_count; void ot(const char *format, ...) @@ -90,24 +90,22 @@ static void PrintException(int ints) ot(" mov r11,r0\n"); } - ot(";@ swap OSP <-> A7?\n"); ot(" ldr r0,[r7,#0x44] ;@ Get SR high\n"); + ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); ot(" tst r0,#0x20\n"); - ot(" bne no_sp_swap%i\n",ints); - ot(";@ swap OSP and A7:\n"); - ot(" ldr r0,[r7,#0x3C] ;@ Get A7\n"); - ot(" ldr r1,[r7,#0x48] ;@ Get OSP\n"); - ot(" str r0,[r7,#0x48]\n"); - ot(" str r1,[r7,#0x3C]\n"); - ot("no_sp_swap%i%s\n",ints,ms?"":":"); + ot(";@ get our SP:\n"); + ot(" ldr r0,[r7,#0x3c] ;@ Get A7\n"); + ot(" ldreq r1,[r7,#0x48] ;@ ...or OSP as our stack pointer\n"); + ot(" streq r0,[r7,#0x48]\n"); + ot(" moveq r0,r1\n"); - ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); -// ot(" mov r1,r4,lsl #8\n"); -// ot(" sub r1,r1,r10,lsl #8 ;@ r1 = Old PC\n"); -// ot(" mov r1,r1,asr #8 ;@ push sign extended\n"); ot(" sub r1,r4,r10 ;@ r1 = Old PC\n"); - OpPush32(); + ot(";@ Push r1 onto stack\n"); + ot(" sub r0,r0,#4 ;@ Predecrement A7\n"); + ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); + MemHandler(1,2); OpPushSr(1); + ot(" mov r0,r11\n"); ot(";@ Read IRQ Vector:\n"); MemHandler(0,2); @@ -122,6 +120,8 @@ static void PrintException(int ints) ot(" mov lr,pc\n"); ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); ot(" mov r4,r0\n"); +#else + ot(" add r4,r0,r10 ;@ r4 = Memory Base + New PC\n"); #endif ot("\n"); @@ -133,21 +133,6 @@ static void PrintException(int ints) } } -// Trashes r0,r1 -void CheckInterrupt(int op) -{ - ot(";@ CheckInterrupt:\n"); - ot(" ldr r1,[r7,#0x44] ;@ Get SR high T_S__III and irq level\n"); - ot(" movs r0,r1,lsr #24 ;@ Get IRQ level\n"); // same as ldrb r0,[r7,#0x47] - ot(" beq NoInts%x\n",op); - ot(" cmp r0,#6 ;@ irq>6 ?\n"); - ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); - ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); - ot(" blgt CycloneDoInterrupt\n"); - ot("NoInts%x%s\n", op,ms?"":":"); - ot("\n"); -} - void FlushPC(void) { #if MEMHANDLERS_NEED_PC @@ -182,10 +167,7 @@ static void PrintFramework() ot(" cmp r0,#6 ;@ irq>6 ?\n"); ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); - ot(" blgt CycloneDoInterrupt\n"); - ot(";@ Check if interrupt used up all the cycles:\n"); - ot(" subs r5,r5,#0\n"); - ot(" blt CycloneEndNoBack\n"); + ot(" bgt CycloneDoInterrupt\n"); ot("NoInts0%s\n", ms?"":":"); ot("\n"); ot(";@ Check if our processor is in stopped state and jump to opcode handler if not\n"); @@ -341,9 +323,9 @@ static void PrintFramework() #endif ot(";@ DoInterrupt - r0=IRQ number\n"); + ot("CycloneDoInterruptGoBack%s\n", ms?"":":"); + ot(" sub r4,r4,#2\n"); ot("CycloneDoInterrupt%s\n", ms?"":":"); - ot(" stmdb sp!,{lr} ;@ Push ARM return address\n"); - ot(";@ Get IRQ Vector address:\n"); ot(" mov r0,r0,asl #2\n"); ot(" add r11,r0,#0x60\n"); @@ -356,7 +338,6 @@ static void PrintFramework() ot(";@ Clear stopped states:\n"); ot(" str r2,[r7,#0x58]\n"); - ot(" sub r5,r5,#%d ;@ Subtract cycles\n",44); ot("\n"); #if USE_INT_ACK_CALLBACK #if INT_ACK_NEEDS_STUFF @@ -375,11 +356,14 @@ static void PrintFramework() ot(" mov r9,r9,lsl #28\n"); ot(" ldr r4,[r7,#0x40] ;@ Load PC\n"); #endif -#else // not USE_INT_ACK_CALLBACK +#else // !USE_INT_ACK_CALLBACK ot(";@ Clear irq:\n"); - ot(" strb r1,[r7,#0x47]\n"); + ot(" strb r2,[r7,#0x47]\n"); #endif - ot(" ldmia sp!,{pc} ;@ Return\n"); + ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); + ot(" subs r5,r5,#44 ;@ Subtract cycles\n"); + ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); + ot(" b CycloneEnd\n"); ot("\n"); ot("Exception%s\n", ms?"":":"); diff --git a/cpu/Cyclone/OpAny.cpp b/cpu/Cyclone/OpAny.cpp index 8e120154..cbdf5bb2 100644 --- a/cpu/Cyclone/OpAny.cpp +++ b/cpu/Cyclone/OpAny.cpp @@ -25,35 +25,85 @@ void OpUse(int op,int use) ot(";@ ---------- [%.4x] %s uses Op%.4x ----------\n",op,text,use); } -void OpStart(int op, int sea, int tea) +void OpStart(int op, int sea, int tea, int op_changes_cycles, int supervisor_check) { + int last_op_count=arm_op_count; + Cycles=0; OpUse(op,op); // This opcode obviously uses this handler ot("Op%.4x%s\n", op, ms?"":":"); -#if (MEMHANDLERS_NEED_PREV_PC || MEMHANDLERS_NEED_CYCLES) - if ((sea >= 0x10 && sea != 0x3c) || (tea >= 0x10 && tea != 0x3c)) { + + if (supervisor_check) + { + // checks for supervisor bit, if not set, jumps to SuperEnd() + // also sets r11 to SR high value, SuperChange() uses this + ot(" ldr r11,[r7,#0x44] ;@ Get SR high\n"); + } + if ((sea >= 0x10 && sea != 0x3c) || (tea >= 0x10 && tea != 0x3c)) + { #if MEMHANDLERS_NEED_PREV_PC ot(" str r4,[r7,#0x50] ;@ Save prev PC + 2\n"); #endif #if MEMHANDLERS_NEED_CYCLES ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); #endif - ot("\n"); } + if (supervisor_check) + { + ot(" tst r11,#0x20 ;@ Check we are in supervisor mode\n"); + ot(" beq WrongPrivilegeMode ;@ No\n"); + } + if ((sea >= 0x10 && sea != 0x3c) || (tea >= 0x10 && tea != 0x3c)) { +#if MEMHANDLERS_CHANGE_CYCLES + if (op_changes_cycles) + ot(" mov r5,#0\n"); #endif + } + if (last_op_count!=arm_op_count) + ot("\n"); pc_dirty = 1; } -void OpEnd(int sea, int tea) +void OpEnd(int sea, int tea, int op_changes_cycles, int check_interrupt) { + int did_fetch=0; #if MEMHANDLERS_CHANGE_CYCLES if ((sea >= 0x10 && sea != 0x3c) || (tea >= 0x10 && tea != 0x3c)) - ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); + { + if (op_changes_cycles) + { + ot(" ldr r0,[r7,#0x5c] ;@ Load Cycles\n"); + ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); + ot(" add r5,r0,r5\n"); + did_fetch=1; + } + else + { + ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); + } + } #endif - ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); + if (!did_fetch) + ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); ot(" subs r5,r5,#%d ;@ Subtract cycles\n",Cycles); - ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot(" b CycloneEnd\n"); + if (check_interrupt) + { + ot(" blt CycloneEnd\n"); + ot(";@ CheckInterrupt:\n"); + ot(" ldr r1,[r7,#0x44] ;@ Get SR high T_S__III and irq level\n"); + ot(" movs r0,r1,lsr #24 ;@ Get IRQ level\n"); // same as ldrb r0,[r7,#0x47] + ot(" ldreq pc,[r6,r8,asl #2] ;@ Jump to next opcode handler\n"); + ot(" cmp r0,#6 ;@ irq>6 ?\n"); + ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); + ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); + ot(" ldrle pc,[r6,r8,asl #2] ;@ Jump to next opcode handler\n"); + ot(" b CycloneDoInterruptGoBack\n"); + } + else + { + ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); + ot(" b CycloneEnd\n"); + } ot("\n"); } diff --git a/cpu/Cyclone/OpBranch.cpp b/cpu/Cyclone/OpBranch.cpp index d1c23918..320b898b 100644 --- a/cpu/Cyclone/OpBranch.cpp +++ b/cpu/Cyclone/OpBranch.cpp @@ -4,7 +4,7 @@ static void CheckPc(int reg) { #if USE_CHECKPC_CALLBACK - ot(";@ Check Memory Base+pc (r4)\n"); + ot(";@ Check Memory Base+pc (r%i)\n",reg); if (reg != 0) ot(" mov r0,r%i\n", reg); ot(" mov lr,pc\n"); @@ -173,14 +173,12 @@ int Op4E70(int op) return 0; case 3: // rte - OpStart(op,0x10); Cycles=20; - SuperCheck(op); + OpStart(op,0x10,0,0,1); Cycles=20; PopSr(1); ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n"); PopPc(); SuperChange(op); - CheckInterrupt(op); - OpEnd(0x10); + OpEnd(0x10,0,0,1); return 0; case 5: // rts @@ -191,12 +189,12 @@ int Op4E70(int op) return 0; case 6: // trapv - OpStart(op,0x10); Cycles=4; + OpStart(op,0x10,0,1); Cycles=4; ot(" tst r9,#0x10000000\n"); ot(" subne r5,r5,#%i\n",34); ot(" movne r0,#0x1c ;@ TRAPV exception\n"); ot(" blne Exception\n"); - OpEnd(0x10); + OpEnd(0x10,0,1); return 0; case 7: // rtr @@ -233,27 +231,19 @@ int OpJsr(int op) ot("\n"); EaCalc(11,0x003f,sea,0); - ot(";@ Jump - Get new PC from r0\n"); - if (op&0x40) - { - // Jmp - Get new PC from r11 - ot(" add r0,r11,r10 ;@ Memory Base + New PC\n"); - ot("\n"); - } - else + if (!(op&0x40)) { ot(";@ Jsr - Push old PC first\n"); ot(" ldr r0,[r7,#0x3c]\n"); ot(" sub r1,r4,r10 ;@ r1 = Old PC\n"); -// ot(" mov r1,r1,lsl #8\n"); -// ot(" mov r1,r1,asr #8\n"); ot(";@ Push r1 onto stack\n"); ot(" sub r0,r0,#4 ;@ Predecrement A7\n"); ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); MemHandler(1,2); - ot(" add r0,r11,r10 ;@ Memory Base + New PC\n"); - ot("\n"); } + ot(";@ Jump - Get new PC from r11\n"); + ot(" add r0,r11,r10 ;@ Memory Base + New PC\n"); + ot("\n"); CheckPc(0); @@ -441,8 +431,6 @@ int OpBranch(int op) ot(" ldr r2,[r7,#0x3c]\n"); ot(" sub r1,r4,r10 ;@ r1 = Old PC\n"); if (size) ot(" add r1,r1,#%d\n",1<=2; + OpStart(op,ea,0,changed_cycles); Cycles=8; if (ea<8) Cycles=4; if (cc) @@ -362,7 +363,7 @@ int OpSet(int op) EaCalc (0,0x003f, ea,size,0,0); EaWrite(0, 1, ea,size,0x003f,0,0); - OpEnd(ea); + OpEnd(ea,0,changed_cycles); return 0; } @@ -586,7 +587,6 @@ int OpAsr(int op) int count=0,dir=0; int size=0,usereg=0,type=0; - ea=0; count =(op>>9)&7; dir =(op>>8)&1; size =(op>>6)&3; @@ -605,7 +605,7 @@ int OpAsr(int op) 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,1); EaRead(10, 0, ea,size,0x0007,1); @@ -614,7 +614,7 @@ int OpAsr(int op) EaWrite(10, 0, ea,size,0x0007,1); - OpEnd(); + OpEnd(ea,0,count<0); return 0; } diff --git a/cpu/Cyclone/OpMove.cpp b/cpu/Cyclone/OpMove.cpp index b0916ea6..64c0f59f 100644 --- a/cpu/Cyclone/OpMove.cpp +++ b/cpu/Cyclone/OpMove.cpp @@ -39,16 +39,6 @@ void OpRegToFlags(int high) ot("\n"); } -// checks for supervisor bit, if not set, jumps to SuperEnd() -// also sets r11 to SR high value, SuperChange() uses this -void SuperCheck(int op) -{ - ot(" ldr r11,[r7,#0x44] ;@ Get SR high\n"); - ot(" tst r11,#0x20 ;@ Check we are in supervisor mode\n"); - ot(" beq WrongPrivilegeMode ;@ No\n"); - ot("\n"); -} - void SuperEnd(void) { ot(";@ ----------\n"); @@ -58,7 +48,7 @@ void SuperEnd(void) ot(" mov r0,#0x20 ;@ privilege violation\n"); ot(" bl Exception\n"); Cycles=34; - OpEnd(0x10); + OpEnd(0); } // does OSP and A7 swapping if needed @@ -217,12 +207,11 @@ int OpMoveSr(int op) use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op,ea); + // 68000 model allows reading whole SR in user mode (but newer models don't) + OpStart(op,ea,0,0,type==3); Cycles=12; if (type==0) Cycles=(ea>=8)?8:6; - if (type==3) SuperCheck(op); // 68000 model allows reading whole SR in user mode (but newer models don't) - if (type==0 || type==1) { OpFlagsToReg(type==0); @@ -236,11 +225,10 @@ int OpMoveSr(int op) OpRegToFlags(type==3); if (type==3) { SuperChange(op,0); - CheckInterrupt(op); } } - OpEnd(ea); + OpEnd(ea,0,0,type==3); return 0; } @@ -259,9 +247,7 @@ int OpArithSr(int op) use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op,ea); Cycles=16; - - if (size) SuperCheck(op); + OpStart(op,ea,0,0,size!=0); Cycles=16; EaCalc(10,0x003f,ea,size); EaRead(10, 10,ea,size,0x003f); @@ -271,12 +257,11 @@ int OpArithSr(int op) if (type==1) ot(" and r0,r1,r10\n"); if (type==5) ot(" eor r0,r1,r10\n"); OpRegToFlags(size); - if (size) { + if (size && type!=0) { // we can't enter supervisor mode, nor unmask irqs just by using OR SuperChange(op,0); - CheckInterrupt(op); } - OpEnd(ea); + OpEnd(ea,0,0,size!=0 && type!=0); return 0; } @@ -337,7 +322,7 @@ int OpMovem(int op) use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op,ea); + OpStart(op,ea,0,1); ot(" ldrh r11,[r4],#2 ;@ r11=register mask\n"); @@ -370,6 +355,9 @@ int OpMovem(int op) } else { + // if (size == 2 && decr && SPLIT_MOVEL_PD) we should do 2xWrite16 here + // (same as in movel.l ?, -(An)), but as this is not likely to be needed and + // we do not want the performance hit, we do single Write32 instead. ot(" ;@ Copy register to memory:\n",1<>1)&1; // stop/reset - OpStart(op); - - SuperCheck(op); + OpStart(op,0,0,0,1); if(type) { // copy immediate to SR, stop the CPU and eat all remaining cycles. diff --git a/cpu/Cyclone/app.h b/cpu/Cyclone/app.h index f61432f9..1d437d5b 100644 --- a/cpu/Cyclone/app.h +++ b/cpu/Cyclone/app.h @@ -32,9 +32,9 @@ extern char *Narm[4]; // Normal ARM Extensions for operand sizes 0,1,2 extern char *Sarm[4]; // Sign-extend ARM Extensions for operand sizes 0,1,2 extern int Cycles; // Current cycles for opcode extern int pc_dirty; // something changed PC during processing +extern int arm_op_count; // for stats void ot(const char *format, ...); void ltorg(); -void CheckInterrupt(int op); int MemHandler(int type,int size,int addrreg=0); void FlushPC(void); @@ -42,8 +42,8 @@ void FlushPC(void); extern int g_op; int OpGetFlags(int subtract,int xbit,int sprecialz=0); void OpUse(int op,int use); -void OpStart(int op,int sea=0,int tea=0); -void OpEnd(int sea=0,int tea=0); +void OpStart(int op,int sea=0,int tea=0,int op_changes_cycles=0,int supervisor_check=0); +void OpEnd(int sea=0,int tea=0,int op_changes_cycles=0,int check_interrupt=0); int OpBase(int op,int size,int sepa=0); void OpAny(int op); @@ -100,7 +100,6 @@ int OpMoveUsp(int op); int OpExg(int op); int OpMovep(int op); int OpStopReset(int op); -void SuperCheck(int op); void SuperEnd(void); void SuperChange(int op,int load_srh=1); diff --git a/cpu/Cyclone/config.h b/cpu/Cyclone/config.h index 6fc6571f..24b73a1c 100644 --- a/cpu/Cyclone/config.h +++ b/cpu/Cyclone/config.h @@ -18,7 +18,7 @@ * the write-back phase. That will be emulated, if this option is enabled. * This option also alters timing slightly. */ -#define CYCLONE_FOR_GENESIS 2 +#define CYCLONE_FOR_GENESIS 0 /* * This option compresses Cyclone's jumptable. Because of this the executable @@ -52,13 +52,13 @@ * increment the PC before fetching the next instruction and continue executing * at wrong location. */ -#define MEMHANDLERS_NEED_PC 0 +#define MEMHANDLERS_NEED_PC 1 #define MEMHANDLERS_NEED_PREV_PC 0 #define MEMHANDLERS_NEED_FLAGS 0 #define MEMHANDLERS_NEED_CYCLES 1 #define MEMHANDLERS_CHANGE_PC 0 #define MEMHANDLERS_CHANGE_FLAGS 0 -#define MEMHANDLERS_CHANGE_CYCLES 0 +#define MEMHANDLERS_CHANGE_CYCLES 1 /* * If enabled, Cyclone will call IrqCallback routine from it's context whenever it @@ -79,7 +79,7 @@ * encountered. All context members are valid and can be changed. * If disabled, RESET opcode acts as an NOP. */ -#define USE_RESET_CALLBACK 1 +#define USE_RESET_CALLBACK 0 /* * If enabled, UnrecognizedCallback is called if an invalid opcode is