• R/O
  • HTTP
  • SSH
  • HTTPS

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

This is for exploring and demonstrating ways to extend the available integer math in C. Cコンパイラが提供する整数を拡張するための探険用のソースコードです。


File Info

Révision 056c8c9d381867aa3d96bcf05e9a165e42771547
Taille 6,116 octets
l'heure 2013-07-29 11:34:41
Auteur Joel Matthew Rees
Message de Log

Where I ran out of time last week. Demonstrats add/sub/mul/bitdiv.
C's lack of an overflow target for math (especially division) makes it hard to expand.
But division is hard anyway, and the carry/overflow for the rest really is not that bad.

Content

/* Division functions for an eight-bit framework 
// for testing various arithmetic techniques.
// Written by Joel Matthew Rees
// Copyright 2013, Joel Matthew Rees
// Distribution and use permitted under terms of the GPL v. 3,
// See the included file, LICENSE.TXT,
// or on-line at <http://www.gnu.org/licenses/>. 
*/


#include <stdio.h>
#include <limits.h>


#include "nibBit.h"


/*
01800 USLASH	LDA #17 bit ct
01810 	PSHS A
01820 	LDD 2,U dividend
01830 USLDIV	CMPD ,U divisor
01840 	BHS USLSUB
01850 	ANDCC #.NOT.1
01860 	BRA USLBIT
01870 USLSUB	SUBD ,U
01880 	ORCC #1 quotient,
01890 USLBIT	ROL 5,U save it
01900 	ROL 4,U
01910 	DEC ,S more bits?
01920 	BEQ USLR
01930 	ROLB remainder
01940 	ROLA
01950 	BCC USLDIV
01960 	BRA USLSUB
01970 USLR	LEAS 1,S
01980 	LEAU 2,U
01990 	LDX 2,U
02000 	STD 2,U
02010 	STX ,U
02020 	NEXT
02030 *
*/
/* Push order: dividend-lsbyte dividend-msbyte divisor 
// return order: remainder quotient
// (quotient on top-of-stack -- at low address)
// The high byte of the dividend is a trick to avoid shifting.
// It gets partially discarded, how much depends on the divisor.
*/
void nibBUDiv( void )
{
   unsigned count = BYTEBITS + 1; /* byte wide, so we aren't here all day. */
   uchar_t divisor = ( * mySP++ );
   uchar_t dividendHi = mySP[ 0 ];  /* Thrown away, in part. */
   uchar_t dividendLo = mySP[ 1 ]; 
   uchar_t quotient = 0;
   uchar_t carry = 0;
   for ( ;; )
   {  
      if ( carry || ( dividendHi >= divisor ) ) /* Two's complement only */
      {
         quotient |= 1;
         dividendHi -= divisor;
      }
      if ( --count <= 0 )
      {  break;
      }
      quotient <<= 1;
      carry = dividendHi & BYTEHIBIT;
      dividendHi <<= 1;
      if ( ( dividendLo & BYTEHIBIT ) != 0 )
      {  dividendHi |= 1;
      }
      dividendLo <<= 1;
   }
   mySP[ 0 ] = quotient;
   mySP[ 1 ] = dividendHi; /* At this point, the remainder. */
}
/* When done correctly, catching the carry, etc., 
// divide-by-shift is a covering complement to multiply-by-shift.
//
// That is, the above 16 bit dividend, 8 bit divisor unsigned divide
// covers all the possible results of an 8 bit by 8 bit unsigned multiply.
// (It hits and misses n>8 quotients and m<8 divisor cases.)
//
// If you have a hardware divide equivalent to the above, 
// you can use it (at assembler level) to implement U/, 
// and build M/MOD from U/.
// In other words, an unsigned divide with 
// double word dividend, word divisor, 
// and word quotient and remainder
// can be used to synthesize a full double word result
// using half-word shifting.
// 
// 
// To fully cover all double word divisions and word bit divisors, 
// one might prime the loop with a zero word 
// and shift-divide three words of dividend by double word bit width.
*/


/* Push order: dividend-lsbyte dividend-msbyte divisor 
// return order: remainder quotient
// test return order: remainder-lsbyte remainder-msbyte quotient
// (quotient on top-of-stack -- at low address)
// The high byte of the dividend is a trick to avoid shifting.
// It gets partially discarded, how much depends on the divisor.
*/
void nibUDiv( void )
{
   uchar_t divisor = mySP[ 0 ];
   uchar_t dividendHi = mySP[ 1 ];
   uchar_t dividendLo = mySP[ 2 ];

/*
printf( "start dividendHi: %d, dividendLo: %d, divisor: %d\n", 
        dividendHi, dividendLo, divisor );
*/
   if ( dividendHi == 0 )
   {   /* Short circuit */
      mySP[ 2 ] = dividendLo % divisor;
      mySP[ 1 ] = dividendLo / divisor;
#if defined TESTUDIVHIGHWORD
      mySP[ 0 ] = 0;
/*
printf( "native qHi: %d, qLo: %d, rem: %d\n", 
        mySP[ 0 ], mySP[ 1 ], mySP[ 2 ] );
*/
#else /* !defined TESTUDIVHIGHWORD */
      ++mySP;
#endif /* defined TESTUDIVHIGHWORD */

      return; 
   }
   if ( NIBHI( divisor ) == 0 )
   {  /* This covers the full range of dividends vs. nibble-only divisors. */
      uchar_t quotientHi = dividendHi / divisor; /* throwaway */
      uchar_t carry = dividendHi % divisor; /* 0 .. 0x0f */
      uchar_t dividendMidHi = NIBLOUP( carry ) | NIBHIDOWN ( dividendLo );
      uchar_t quotientMidLo = dividendMidHi / divisor;
      uchar_t quotientLo;
/*
printf( "qHi: %d, dMHi: %d, qMLo: %d, carry: %d\n", 
        quotientHi, dividendMidHi, quotientMidLo, carry );
*/
      carry = dividendMidHi % divisor;
      dividendLo &= NIBLOMASK;
      dividendLo |= NIBLOUP( carry );
      quotientLo = dividendLo / divisor;
/*
printf( "qLo: %d, dLo: %d, carry: %d\n", 
        quotientLo, dividendLo, carry );
*/
      mySP[ 2 ] = dividendLo % divisor;
      mySP[ 1 ] = NIBLOUP( quotientMidLo ) | quotientLo;
#if defined TESTUDIVHIGHWORD
      mySP[ 0 ] = quotientHi;
/*
printf( "nibble qHi: %d, qLo: %d, rem: %d\n", 
        mySP[ 0 ], mySP[ 1 ], mySP[ 2 ] );
*/
#else /* !defined TESTUDIVHIGHWORD */
      ++mySP;
#endif /* defined TESTUDIVHIGHWORD */
      return;
   }
   else
   {  /* Divisor > 0x0f */
      unsigned count = BYTEBITS * 2 + 1; 
      uchar_t quotientHi = 0;
      uchar_t quotientLo = 0;
      uchar_t carry = 0;
      uchar_t dividendLead = 0;
      for ( ;; )
      {  
         if ( carry || ( dividendLead >= divisor ) ) /* 2's complement only */
         {
            quotientLo |= 1;
            dividendLead -= divisor;
         }
         if ( --count <= 0 )
         {  break;
         }
         quotientHi <<= 1;
         if ( ( quotientLo & BYTEHIBIT ) != 0 )
         {  quotientHi |= 1;
         }
         quotientLo <<= 1;
         carry = dividendLead & BYTEHIBIT;
         dividendLead <<= 1;
         if ( ( dividendHi & BYTEHIBIT ) != 0 )
         {  dividendLead |= 1;
         }
         dividendHi <<= 1;
         if ( ( dividendLo & BYTEHIBIT ) != 0 )
         {  dividendHi |= 1;
         }
         dividendLo <<= 1;
      }
      mySP[ 1 ] = quotientLo;
      mySP[ 2 ] = dividendLead; /* At this point, the remainder. */

#if defined TESTUDIVHIGHWORD
      mySP[ 0 ] = quotientHi;
/*
printf( "nibble qHi: %d, qLo: %d, rem: %d\n", 
        mySP[ 0 ], mySP[ 1 ], mySP[ 2 ] );
*/
#else /* !defined TESTUDIVHIGHWORD */
      ++mySP;
#endif /* defined TESTUDIVHIGHWORD */

      return;
   }
}