⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 divc.c

📁 这个是ATM9200的divc源代码,x希望对大家有帮助
💻 C
字号:
/*  Optimal divide-by-contstant code generator
    Advanced RISC Machines
*/


#include <stdio.h>
#include <stdlib.h>

#define BANNER          "generated by Thumb divc 1.00 (Advanced RISC Machines)"
#define DATE            "4 Apr 95"

#define DIVIDE_BY_2_MINUS_1             0
#define DIVIDE_BY_2_PLUS_1              1


typedef unsigned int uint;


uint log2( uint n )
{
  uint bit, pow, logn;

  for( bit = 0, pow = 1; bit < 31; bit++, pow <<= 1 )
  {
    if( n == pow ) logn = bit;
  }

  return( logn );
}


int powerof2( int n )
{
  return( n == ( n & (-n) ) );
}


void dodiv2m1( uint logd, uint logmsb )
{
  /* Output instructions to do division by 2^n - 1 */
  printf( "\tLSR     a1, #1\n");

  while( logd < 32 )
  {
    printf( "\tLSR     a3, a1, #%d\n", logd );
    printf( "\tADD     a1, a3\n");
    logd <<= 1;
  }
  printf( "\tLSR     a1, #%d\n", logmsb - 1);
}


void dodiv2p1( uint logd, uint logmsb )
{
  /* Output instructions to do division by 2^n + 1 */
  printf( "\tLSR     a3, a1, #%d\n", logd);
  printf( "\tSUB     a1, a3\n");

  while( logd < 16 )
  {
    logd <<= 1;
    printf( "\tLSR     a3, a1, #%d\n", logd );
    printf( "\tADD     a1, a3\n");
  }

  printf( "\tLSR     a1, #%d\n", logmsb);
}


void divideby2( uint type, uint n, uint lsb, uint msb )
{
  uint loglsb;
  uint logmsb;

  loglsb = log2( lsb );
  logmsb = log2( msb );

  printf( "; %s [%s]\n\n", BANNER, DATE );
  printf( "\tCODE16\n\n" );
  printf( "\tAREA |div%d$code|, CODE, READONLY\n\n", n );
  printf( "\tEXPORT udiv%d\n\n", n );
  printf( "udiv%d\n", n );
  printf( "; takes argument in a1\n" );
  printf( "; returns quotient in a1, remainder in a2\n" );
  printf( "; cycles could be saved if only divide or remainder is required\n" );

  if (n > 255) {
    fprintf(stderr, "Constant %d too big for divc to handle", n);
    exit(1);
  }
  printf( "\tMOV     a2, a1\n" );

  /* 1/n as a binary number consists of a simple repeating pattern     */
  /* The multiply by 1/n is expanded as a sequence of ARM instructions */
  /* (there is a rounding error which must be corrected later)         */
  switch( type )
  {
  case DIVIDE_BY_2_MINUS_1:
    dodiv2m1( logmsb - loglsb, logmsb );
    /* Now do multiply-by-n */
    printf( "\tASL     a3, a1, #%d\n", logmsb - loglsb );
    printf( "\tSUB     a3, a3, a1\n");
    break;

  case DIVIDE_BY_2_PLUS_1:
    dodiv2p1( logmsb - loglsb, logmsb );
    /* Now do multiply-by-n */
    printf( "\tASL     a3, a1, #%d\n", logmsb - loglsb );
    printf( "\tADD     a3, a1\n" );
    break;
  }

  /* Subtract from adjusted original to obtain remainder */
  printf( "\tASL     a3, #%d\n", loglsb);
  printf( "\tSUB     a2, a3\n");

  /* Apply corrections */
  printf( "\tCMP     a2, #%d\n", n);
  printf( "\tBLT     %%FT0\n");
  printf( "\tADD     a1, #1\n");
  printf( "\tSUB     a2, #%d\n", n);
  printf( "0\n");

  /* Additional test required for divide-by-3, as result could be  */
  /* off by 2 lsb due to accumulated rounding errors.              */
  if( n == 3 )
  {
    printf( "\tCMP     a2, #%d\n", n);
    printf( "\tBLT     %%FT0\n");
    printf( "\tADD     a1, #1\n");
    printf( "\tSUB     a2, #%d\n", n);
    printf( "0\n");
  }

  printf( "\tMOV     pc, lr\n\n" );
  printf( "\tEND\n" );
}


int main( int argc, char *argv[] )
{
  if( argc != 2 )
  {
    printf( "Usage: divc <n>\n" );
    printf( "Generates optimal ARM code for divide-by-constant\n" );
    printf( "where <n> is one of (2^n-2^m) or (2^n+2^m) eg. 10\n" );
    printf( "Advanced RISC Machines [%s]\n", DATE );
  }
  else
  {
    int num;

    num = atoi( argv[ 1 ] );
    if( num <= 1 )
    {
      fprintf( stderr, "%d is not sensible\n", num );
    }
    else
    {
      uint lsb = 1;

      /* find least-significant bit */
      while( ( num & lsb ) == 0 )
      {
        lsb <<= 1;
      }

      if( powerof2( num ) )
      {
        fprintf( stderr, "%d is an easy case\n", num );
      }
      else if( powerof2( num + lsb ) )
      {
        divideby2( DIVIDE_BY_2_MINUS_1, num, lsb, num + lsb );
      }
      else if( powerof2( num - lsb ) )
      {
        divideby2( DIVIDE_BY_2_PLUS_1, num, lsb, num - lsb );
      }
      else
      {
        fprintf( stderr, "%d is not one of (2^n-2^m) or (2^n+2^m)\n", num );
      }
    }
  }
  return( 0 );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -