Annotation of hatari/src/cycles.c, revision 1.1.1.12

1.1       root        1: /*
                      2:   Hatari - cycles.c
                      3: 
1.1.1.9   root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
                      7:   Here we take care of cycle counters. For performance reasons we don't increase
                      8:   all counters after each 68k instruction, but only one main counter.
                      9:   When we need to read one of the normal counters (currently only for video
                     10:   and sound cycles), we simply update these counters with the main counter
                     11:   before returning the current counter value.
                     12: */
1.1.1.2   root       13: 
                     14: 
                     15: /* 2007/03/xx  [NP]    Use 'CurrentInstrCycles' to get a good approximation for        */
                     16: /*                     Cycles_GetCounterOnReadAccess and Cycles_GetCounterOnWriteAccess*/
                     17: /*                     (this should work correctly with 'move' instruction).           */
1.1.1.12! root       18: /* 2008/04/14  [NP]    Take WaitStateCycles into account when computing the value of   */
1.1.1.3   root       19: /*                     Cycles_GetCounterOnReadAccess and Cycles_GetCounterOnWriteAccess*/
1.1.1.4   root       20: /* 2008/12/21  [NP]    Use BusMode to adjust Cycles_GetCounterOnReadAccess and         */
                     21: /*                     Cycles_GetCounterOnWriteAccess depending on who is owning the   */
                     22: /*                     bus (cpu, blitter).                                             */
1.1.1.6   root       23: /* 2011/03/26  [NP]    In Cycles_GetCounterOnReadAccess, add a special case for opcode */
                     24: /*                     $11f8 'move.b xxx.w,xxx.w' (fix MOVE.B $ffff8209.w,$26.w in     */
                     25: /*                     'Bird Mad Girl Show' demo's loader/protection)                  */
1.1.1.9   root       26: /* 2012/08/19  [NP]    Add a global counter CyclesGlobalClockCounter to count cycles   */
                     27: /*                     since the last reset.                                           */
1.1.1.12! root       28: /* 2015/10/04  [NP]    In Cycles_GetInternalCycleOnReadAccess / WriteAccess, use the   */
        !            29: /*                     sub-cycles provided by WinUAE cpu core when using cycle exact   */
        !            30: /*                     mode (instead of using heuristics for the most common opcodes). */
1.1.1.2   root       31: 
                     32: 
1.1.1.4   root       33: const char Cycles_fileid[] = "Hatari cycles.c : " __DATE__ " " __TIME__;
1.1       root       34: 
                     35: #include "main.h"
1.1.1.3   root       36: #include "m68000.h"
1.1.1.5   root       37: #include "memorySnapShot.h"
1.1       root       38: #include "cycles.h"
1.1.1.12! root       39: #include "ioMem.h"
        !            40: #include "hatari-glue.h"
1.1       root       41: 
                     42: 
1.1.1.9   root       43: int    nCyclesMainCounter;                     /* Main cycles counter since previous Cycles_UpdateCounters() */
1.1       root       44: 
1.1.1.5   root       45: static int nCyclesCounter[CYCLES_COUNTER_MAX]; /* Array with all counters */
1.1       root       46: 
1.1.1.9   root       47: Uint64 CyclesGlobalClockCounter = 0;           /* Global clock counter since starting Hatari (it's never reset afterwards) */
1.1.1.7   root       48: 
1.1.1.9   root       49: int    CurrentInstrCycles;
                     50: 
                     51: 
                     52: static void    Cycles_UpdateCounters(void);
1.1.1.2   root       53: 
1.1       root       54: 
1.1.1.5   root       55: 
                     56: /*-----------------------------------------------------------------------*/
                     57: /**
                     58:  * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
                     59:  */
                     60: void Cycles_MemorySnapShot_Capture(bool bSave)
                     61: {
                     62:        /* Save/Restore details */
                     63:        MemorySnapShot_Store(&nCyclesMainCounter, sizeof(nCyclesMainCounter));
                     64:        MemorySnapShot_Store(nCyclesCounter, sizeof(nCyclesCounter));
1.1.1.9   root       65:        MemorySnapShot_Store(&CyclesGlobalClockCounter, sizeof(CyclesGlobalClockCounter));
1.1.1.5   root       66:        MemorySnapShot_Store(&CurrentInstrCycles, sizeof(CurrentInstrCycles));
                     67: }
                     68: 
                     69: 
1.1       root       70: /*-----------------------------------------------------------------------*/
1.1.1.2   root       71: /**
                     72:  * Update all cycles counters with the current value of nCyclesMainCounter.
                     73:  */
1.1       root       74: static void Cycles_UpdateCounters(void)
                     75: {
                     76:        int i;
                     77: 
                     78:        for (i = 0; i < CYCLES_COUNTER_MAX; i++)
                     79:        {
                     80:                nCyclesCounter[i] += nCyclesMainCounter;
                     81:        }
                     82: 
                     83:        nCyclesMainCounter = 0;
                     84: }
                     85: 
                     86: 
                     87: /*-----------------------------------------------------------------------*/
1.1.1.2   root       88: /**
                     89:  * Set a counter to a new value.
                     90:  */
1.1       root       91: void Cycles_SetCounter(int nId, int nValue)
                     92: {
                     93:        /* Update counters first (nCyclesMainCounter must be 0 afterwards) */
                     94:        Cycles_UpdateCounters();
                     95: 
                     96:        /* Now set the new value: */
                     97:        nCyclesCounter[nId] = nValue;
                     98: }
                     99: 
                    100: 
                    101: /*-----------------------------------------------------------------------*/
1.1.1.2   root      102: /**
                    103:  * Read a counter.
                    104:  */
1.1       root      105: int Cycles_GetCounter(int nId)
                    106: {
                    107:        /* Update counters first so we read an up-to-date value */
                    108:        Cycles_UpdateCounters();
                    109: 
                    110:        return nCyclesCounter[nId];
                    111: }
                    112: 
                    113: 
                    114: /*-----------------------------------------------------------------------*/
1.1.1.2   root      115: /**
1.1.1.9   root      116:  * Compute the cycles where a read actually happens inside a specific
                    117:  * instruction type. We use some common cases, this should be handled more
                    118:  * accurately in the cpu emulation for each opcode.
1.1.1.2   root      119:  */
1.1.1.12! root      120: int Cycles_GetInternalCycleOnReadAccess(void)
1.1       root      121: {
1.1.1.9   root      122:        int AddCycles;
1.1.1.6   root      123:        int Opcode;
1.1       root      124: 
1.1.1.4   root      125:        if ( BusMode == BUS_MODE_BLITTER )
                    126:        {
1.1.1.12! root      127:                AddCycles = 4 + WaitStateCycles;
1.1.1.4   root      128:        }
1.1.1.12! root      129: #ifdef WINUAE_FOR_HATARI
        !           130:        /* When using WinUAE CPU in CE mode, 'currcycle' will be the number of cycles */
        !           131:        /* inside the current opcode just before accessing memory. */
        !           132:        /* As memory accesses take 4 cycles, we just need to add 4 cycles to get */
        !           133:        /* the number of cycles when the read will be completed. */
        !           134:        /* (see mem_access_delay_XXX_read() in cpu_prefetch.h and wait_cpu_cycle_read() in custom.c) */
        !           135:        else if ( currprefs.cpu_cycle_exact )
        !           136:        {
        !           137:                AddCycles = currcycle*2/CYCLE_UNIT + 4;
        !           138:        }
        !           139: #endif
1.1.1.4   root      140:        else                                                    /* BUS_MODE_CPU */
                    141:        {
1.1.1.11  root      142:                /* TODO: Find proper cycles count depending on the opcode/family of the current instruction */
1.1.1.4   root      143:                /* (e.g. movem is not correctly handled) */
1.1.1.11  root      144:                Opcode = M68000_CurrentOpcode;
1.1.1.6   root      145: 
                    146:                /* Assume we use 'move src,dst' : access cycle depends on dst mode */
1.1.1.12! root      147:                if ( Opcode == 0x11f8 )                                                 /* move.b xxx.w,xxx.w (eg MOVE.B $ffff8209.w,$26.w in Bird Mad Girl Show) */
        !           148:                        AddCycles = 8 + WaitStateCycles;                                /* read is effective after 8 cycles */
        !           149: 
        !           150:                else if ( OpcodeFamily == i_MVPRM )                                     /* movep.l d0,$ffc3(a1) in E605 (STE) or movep.l d1,$fffb(a2) in RGBeast (STE) */
        !           151:                        AddCycles = 4 + IoAccessInstrCount * 4 + WaitStateCycles;       /* [NP] FIXME, it works with RGBeast, but not with E605 */
1.1.1.7   root      152:                                                                                        /* something must be wrong in video.c */
1.1.1.12! root      153: 
        !           154:                else                                                                    /* assume the behaviour of a 'move' to Dn */
        !           155:                        AddCycles = CurrentInstrCycles - 4 + WaitStateCycles;           /* read is effective 4 cycles before the end of the instr */
1.1.1.4   root      156:        }
1.1       root      157: 
1.1.1.9   root      158:        return AddCycles;
1.1       root      159: }
                    160: 
                    161: 
1.1.1.9   root      162: 
1.1       root      163: /*-----------------------------------------------------------------------*/
1.1.1.2   root      164: /**
1.1.1.9   root      165:  * Compute the cycles where a write actually happens inside a specific
                    166:  * instruction type. We use some common cases, this should be handled more
                    167:  * accurately in the cpu emulation for each opcode.
1.1.1.2   root      168:  */
1.1.1.12! root      169: int Cycles_GetInternalCycleOnWriteAccess(void)
1.1       root      170: {
1.1.1.9   root      171:        int AddCycles;
1.1       root      172: 
1.1.1.4   root      173:        if ( BusMode == BUS_MODE_BLITTER )
                    174:        {
1.1.1.12! root      175:                AddCycles = 4 + WaitStateCycles;
1.1.1.4   root      176:        }
1.1.1.12! root      177: #ifdef WINUAE_FOR_HATARI
        !           178:        /* When using WinUAE CPU in CE mode, 'currcycle' will be the number of cycles */
        !           179:        /* inside the current opcode just before accessing memory. */
        !           180:        /* As memory accesses take 4 cycles, we just need to add 4 cycles to get */
        !           181:        /* the number of cycles when the write will be completed. */
        !           182:        /* (see mem_access_delay_XXX_write() in cpu_prefetch.h and wait_cpu_cycle_write() in custom.c) */
        !           183:        else if ( currprefs.cpu_cycle_exact )
        !           184:        {
        !           185:                AddCycles = currcycle*2/CYCLE_UNIT + 4;
        !           186:        }
        !           187: #endif
1.1.1.4   root      188:        else                                                    /* BUS_MODE_CPU */
                    189:        {
                    190:                /* TODO: Find proper cycles count depending on the type of the current instruction */
                    191:                /* (e.g. movem is not correctly handled) */
1.1.1.12! root      192:                AddCycles = CurrentInstrCycles + WaitStateCycles;
1.1.1.4   root      193: 
1.1.1.10  root      194:                if ( ( OpcodeFamily == i_CLR ) || ( OpcodeFamily == i_NEG ) || ( OpcodeFamily == i_NEGX ) || ( OpcodeFamily == i_NOT ) )
                    195:                        ;                                               /* Do nothing, the write is done during the last 4 cycles */
                    196:                                                                        /* (e.g i_CLR for bottom border removal in No Scroll / Delirious Demo 4) */
                    197: 
                    198:                else if ( ( OpcodeFamily == i_ADD ) || ( OpcodeFamily == i_SUB ) )
                    199:                        ;                                               /* Do nothing, the write is done during the last 4 cycles */
                    200:                                                                        /* (eg 'add d1,(a0)' in rasters.prg by TOS Crew */
                    201: 
                    202:                else if ( ( OpcodeFamily == i_AND ) || ( OpcodeFamily == i_OR ) || ( OpcodeFamily == i_EOR ) )
1.1.1.7   root      203:                        ;                                               /* Do nothing, the write is done during the last 4 cycles */
1.1.1.8   root      204: 
                    205:                else if ( ( OpcodeFamily == i_BCHG ) || ( OpcodeFamily == i_BCLR ) || ( OpcodeFamily == i_BSET ) )
                    206:                        ;                                               /* Do nothing, the write is done during the last 4 cycles */
                    207: 
1.1.1.12! root      208:                else if ( OpcodeFamily == i_MVPRM )                     /* movep.l d0,$ffc3(a1) in E605 (STE) or movep.l d1,$fffb(a2) in RGBeast (STE) */
        !           209:                        AddCycles = 4 + IoAccessInstrCount * 4 + WaitStateCycles;       /* [NP] FIXME, it works with RGBeast, but not with E605 */
        !           210: 
        !           211:                else if ( OpcodeFamily == i_MVMLE )
        !           212:                {
        !           213:                        /* In the case of movem, CurrentInstrCycles is dynamic (depends on the number */
        !           214:                        /* of registers to transfer). The 4*n for .W or 8*n for .L is not counted in CurrentInstrCycles */
        !           215:                        /* The last 4 cycles of a movem are for prefetch, so number of cycles is : */
        !           216:                        /* x + 4*n + 4 (movem.w) or x + 8*n + 4 (movem.l)  with x + 4 = CurrentInstrCycles */
        !           217: 
        !           218:                        if (nIoMemAccessSize == SIZE_LONG)              /* long access from a movem.l */
        !           219:                        {
        !           220:                                //AddCycles += -4 + IoAccessInstrCount * 8 - 4;
        !           221:                                AddCycles -= 0;                         /* NOTE [NP] : this is used by old uae cpu core but does not happen */
        !           222:                                                                        /* on real HW because IO regs can't be accessesed with a long */
        !           223:                                                                        /* FIXME : fix old uae cpu to remove long accesses to memory for 68000 ? */
        !           224:                                                                        /* We keep it this way fo now ... */
        !           225:                        }
        !           226:                        else                                            /* word access with movem.w or movem.l doing 2 words accesses per long */
        !           227:                        {
        !           228:                                AddCycles += -4 + IoAccessInstrCount * 4;
        !           229:                        }
        !           230:                }
        !           231: 
1.1.1.7   root      232:                else
                    233:                {
1.1.1.12! root      234:                        /* Default case : write first, then prefetch (mostly for 'move' since this is the most */
1.1.1.7   root      235:                        /* common instr used when requiring cycle precise writes) */
1.1.1.12! root      236:                        if (nIoMemAccessSize == SIZE_LONG)      /* long access */
        !           237:                                AddCycles -= 8;
        !           238:                        else                                    /* word/byte access */
        !           239:                        {
        !           240:                                if ( IoAccessInstrCount == 0 )  /* instruction does only 1 access */
        !           241:                                        AddCycles -= 4;
        !           242:                                else                            /* instruction does multiple accesses (eg: move.l gives 2 word accesses) */
        !           243:                                        AddCycles += -12 + IoAccessInstrCount * 4;      /* gives -8 or -4 */
        !           244:                        }
1.1.1.7   root      245:                }
1.1.1.4   root      246:        }
1.1       root      247: 
1.1.1.9   root      248:        return AddCycles;
                    249: }
                    250: 
                    251: 
                    252: /*-----------------------------------------------------------------------*/
                    253: /**
                    254:  * Read a counter on CPU memory read access by taking care of the instruction
                    255:  * type (add the needed amount of additional cycles).
                    256:  */
                    257: int Cycles_GetCounterOnReadAccess(int nId)
                    258: {
                    259:        int AddCycles;
                    260: 
                    261:        AddCycles = Cycles_GetInternalCycleOnReadAccess();
                    262: 
                    263:        return Cycles_GetCounter(nId) + AddCycles;
                    264: }
                    265: 
                    266: 
                    267: /*-----------------------------------------------------------------------*/
                    268: /**
                    269:  * Read a counter on CPU memory write access by taking care of the instruction
                    270:  * type (add the needed amount of additional cycles).
                    271:  */
                    272: int Cycles_GetCounterOnWriteAccess(int nId)
                    273: {
                    274:        int AddCycles;
                    275: 
                    276:        AddCycles = Cycles_GetInternalCycleOnWriteAccess();
                    277: 
                    278:        return Cycles_GetCounter(nId) + AddCycles;
1.1       root      279: }
1.1.1.9   root      280: 
                    281: 
                    282: /*-----------------------------------------------------------------------*/
                    283: /**
                    284:  * Read the main clock counter on CPU memory read access by taking care of the instruction
                    285:  * type (add the needed amount of additional cycles).
                    286:  */
                    287: Uint64 Cycles_GetClockCounterOnReadAccess(void)
                    288: {
                    289:        int AddCycles;
                    290: 
                    291:        AddCycles = Cycles_GetInternalCycleOnReadAccess();
                    292: 
                    293:        return CyclesGlobalClockCounter + AddCycles;
                    294: }
                    295: 
                    296: 
                    297: /*-----------------------------------------------------------------------*/
                    298: /**
                    299:  * Read the main clock counter on CPU memory write access by taking care of the instruction
                    300:  * type (add the needed amount of additional cycles).
                    301:  */
                    302: Uint64 Cycles_GetClockCounterOnWriteAccess(void)
                    303: {
                    304:        int AddCycles;
                    305: 
                    306:        AddCycles = Cycles_GetInternalCycleOnWriteAccess();
                    307: 
                    308:        return CyclesGlobalClockCounter + AddCycles;
                    309: }
                    310: 
                    311: 
                    312: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.