68000 DIVU/DIVS cycle accurate timing

Latest news in the Atari world

Moderators: Mug UK, Silver Surfer, Moderator Team

ijor
Hardware Guru
Hardware Guru
Posts: 3854
Joined: Sat May 29, 2004 7:52 pm
Contact:

68000 DIVU/DIVS cycle accurate timing

Postby ijor » Thu Jun 30, 2005 7:29 pm

I solved the undocumented timing of the 68000 DIVU/DIVS instructions:

Below is attached source code for computing the exact number of cycles taken by a specific division on the Motorola 68000 CPU. As far as I know this information was not (publicly) available before.

Current emulators for 68000-based machines (Amiga, Atari ST, MAC, MAME, etc) reached an amazing level of accuracy. The exact timing of the division instructions remained as one of the main inaccuracies because this is not documented in the available manuals. Hopefully, with this issue solved now, 68000 emulation can take one-step forward.

The code and algorithm was only partially tested. It is not feasible to do an exhaustive test on real hardware in a single machine.

The source code below is also available at:

http://pasti.fxatari.com/docs/div68kCycleAccurate.c

Code: Select all


/*
 * Compute exact number of CPU cycles taken
 * by DIVU and DIVS on a 68000 processor.
 *
 * Copyright (c) 2005 by Jorge Cwik, pasti@fxatari.com
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


/*

 The routines below take dividend and divisor as parameters.
 They return 0 if division by zero, or exact number of cycles otherwise.

 The number of cycles returned assumes a register operand.
 Effective address time must be added if memory operand.

 For 68000 only (not 68010, 68012, 68020, etc).
 Probably valid for 68008 after adding the extra prefetch cycle.


 Best and worst cases for register operand:
 (Note the difference with the documented range.)


 DIVU:

 Overflow (always): 10 cycles.
 Worst case: 136 cycles.
 Best case: 76 cycles.


 DIVS:

 Absolute overflow: 16-18 cycles.
 Signed overflow is not detected prematurely.

 Worst case: 156 cycles.
 Best case without signed overflow: 122 cycles.
 Best case with signed overflow: 120 cycles

 
 */



// Change this depending on architecture
// This code assumes long is 32 bits and short is 16 bits

typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef signed long LONG;
typedef signed short SHORT;


//
// DIVU
// Unsigned division
//

unsigned getDivu68kCycles( DWORD dividend, WORD divisor)
{
   unsigned mcycles;
   DWORD hdivisor;
   int i;

   if( (WORD) divisor == 0)
      return 0;

   // Overflow
   if( (dividend >> 16) >= divisor)
      return (mcycles = 5) * 2;

   mcycles = 38;
   hdivisor = divisor << 16;

   for( i = 0; i < 15; i++)
   {
      DWORD temp;
      temp = dividend;

      dividend <<= 1;

      // If carry from shift
      if( (LONG) temp < 0)
      {
         dividend -= hdivisor;
      }

      else
      {
         mcycles += 2;
         if( dividend >= hdivisor)
         {
            dividend -= hdivisor;
            mcycles--;
         }
      }
   }

   return mcycles * 2;
}

//
// DIVS
// Signed division
//

unsigned getDivs68kCycles( LONG dividend, SHORT divisor)
{
   unsigned mcycles;
   unsigned aquot;
   int i;

   if( (SHORT) divisor == 0)
      return 0;

   mcycles = 6;

   if( dividend < 0)
      mcycles++;

   // Check for absolute overflow
   if( ((DWORD) abs( dividend) >> 16) >= (WORD) abs( divisor))
   {
      return (mcycles + 2) * 2;
   }

   // Absolute quotient
   aquot = (DWORD) abs( dividend) / (WORD) abs( divisor);

   mcycles += 55;

   if( divisor >= 0)
   {
      if( dividend >= 0)
         mcycles--;
      else
         mcycles++;
   }

   // Count 15 msbits in absolute of quotient

   for( i = 0; i < 15; i++)
   {
      if( (SHORT) aquot >= 0)
         mcycles++;
      aquot <<= 1;
   }


   return mcycles * 2;
}



EDIT: Corrected typo in the comment describing short size. Obviouslly 16 bits and not 32 bits.
Last edited by ijor on Thu Jun 30, 2005 8:25 pm, edited 1 time in total.

Zippy
Captain Atari
Captain Atari
Posts: 192
Joined: Sun Feb 01, 2004 1:58 am

Postby Zippy » Thu Jun 30, 2005 8:09 pm

Fantastic work! So War Heli might work in Steem now? :)

ijor
Hardware Guru
Hardware Guru
Posts: 3854
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Thu Jun 30, 2005 8:32 pm

Zippy wrote:So War Heli might work in Steem now? :)


Hmm. Steem 3.2 already runs your crack of War Heli. Or you mean the original (which we don't have yet :( ?

As I recall the problem with earlier versions was not related to CPU timing but to an inaccuracy of the exception frame. There is also an issue of disk read timing, you need to enable Pasti or enable "Accurate disk time" if using Steem's internal FDC emulator.

There is one demo (polish, I think) discussed here some time ago that is affected. It runs, at least partially with Saint but crashes with Steem. It combines the CopyLock packer with the timing of the current video address value ... plus there is a division in the code as well. Apparentely it runs under Saint just by luck, Leonard choosed a different (than Steem) fixed DIVU setting that is closer to the real one in this specific case.

Zippy
Captain Atari
Captain Atari
Posts: 192
Joined: Sun Feb 01, 2004 1:58 am

Postby Zippy » Thu Jun 30, 2005 8:44 pm

ijor wrote:Steem 3.2 already runs your crack of War Heli.


It doesn't work for me... I just tried it again there, Steem 3.2 and Pasti enabled on "max accuracy" and it crashes a few seconds after you hit space to start loading.

Zippy
Captain Atari
Captain Atari
Posts: 192
Joined: Sun Feb 01, 2004 1:58 am

Postby Zippy » Thu Jun 30, 2005 8:52 pm

Ha! I just set it to 2MB instead of 14MB ram and it works fine now. :)


Social Media

     

Return to “News & Announcements”

Who is online

Users browsing this forum: No registered users and 3 guests