How to calculate with 32 Bit variables => 64 Bit needed

General discussion on mikroC.
Post Reply
Author
Message
Stroi
Posts: 21
Joined: 30 Jul 2007 22:29

How to calculate with 32 Bit variables => 64 Bit needed

#1 Post by Stroi » 13 Dec 2008 20:09

Hello!

I want to make a calculation of a Frequency for a DDS Chip.
I've got a simple formula: Freq = 20.000.000 * FRegister / 2^32

All variables are of unsigned long. The result has to be unsigned long.
How can I make this calculation???

Has anyone an idea? I'ld need a 64Bit calculation.

If it's not possible, what's with a floating point calculation? (=> double)
How can I convert from an unsigned Long to a double and the other way round?

Thanks a lot in advance!!!

Michael

womai
Posts: 239
Joined: 16 Apr 2008 07:45

#2 Post by womai » 14 Dec 2008 00:41

You can't do this calculation with just 32 bit numbers, as you correctly realized.

Floating point calculation won't be too helpful either - MikroC only knows single precision floats, which best case yield only around 7 significant digits. Double precision got promised a long time ago but still isn't implemented.

I have the same problem (also need to calculate the tuning word for a DDS chip, and mine has a 6 byte tuning word!), and I think I will have to write some integer routines for 12-byte-long integers myself.

Stroi
Posts: 21
Joined: 30 Jul 2007 22:29

#3 Post by Stroi » 15 Dec 2008 09:02

Well, and I thought I have a problem :)
12 byte integers sounds like tough work!

Do you have an idea how to write such a routine?
How does a simple multliplikation work?

EC3AEL
Posts: 15
Joined: 11 Dec 2008 09:01

#4 Post by EC3AEL » 15 Dec 2008 12:00

Hi All!

I faced similar problem some tinme ago with 8051 and bascom.
Here are the basic code i used to multiply and divide 8 bytes numbers.
It is (more or less) easy to port into C

Regards Jorge

Code: Select all

'*************************************
' variables declare in the subroutines
'*************************************
Dim Rot(8) As Byte
Dim Restado(8) As Byte
Dim Restando(8) As Byte
Dim Res(8) As Byte
Dim Denominador(8) As Byte
Dim Numerador(8) As Byte
Dim Divisor(8) As Byte
Dim Resto(8) As Byte
Dim Cont1 As Byte
Dim Cont2 As Byte
Dim Aux1 As Byte
Dim Aux2 As Integer
Dim Aux3 As Integer
Dim Aux4 As Long
Dim Aux5 As Long

'*************************************
' general variables
'*************************************
Dim Carry As Byte
Dim Zero As Byte
Dim Kn As Byte
Dim Kw As Byte
Dim Index As Byte

Declare Sub Leftshift()
Declare Sub Subtract()
Declare Sub Divide()
Declare Sub Multiply()

Denominador(1) = &H16
Denominador(2) = &H25
Denominador(3) = &H02
Denominador(4) = &H01
Denominador(5) = 0
Denominador(6) = 0
Denominador(7) = 0
Denominador(8) = 0
Numerador(1) = &H18
Numerador(2) = &H18
Numerador(3) = &H18
Numerador(4) = &H18
Numerador(5) = 0
Numerador(6) = 0
Numerador(7) = 0
Numerador(8) = 0
Carry = 1

Call Multiply()
End




'****************************************************
' Subroutine to Multiply Numerador and Denominador
' the result is in Divisor in 64 bits aritmethics
'****************************************************
Sub Multiply()
   Aux4 = 0
   For Cont1 = 1 To 8
      For Cont2 = Cont1 To 1 Step -1
         Aux1 = Cont1 + 1
         Aux1 = Aux1 - Cont2
         Aux5 = Denominador(cont2)
         Aux5 = Aux5 * Numerador(aux1)
         Aux4 = Aux4 + Aux5
      Next Cont2
      Divisor(cont1) = Low(aux4)
      Shift Aux4 , Right , 8
   Next Cont1
End Sub


'****************************************************
' Subroutine to Divide Numerador over Denominador and
' the result is in Divisor and Resto in 64 bits
' aritmethics
'****************************************************
Sub Divide()
   Kw = 64
   Carry = 0
   'error check
   'calculate kn number of significant bits in Numerador
   Resto(3) = 1
   For Cont1 = 1 To 8
      For Aux1 = 0 To 7
            Resto(1) = 1
            Shift Resto(1) , Left , Aux1
            Resto(2) = Numerador(cont1) And Resto(1)
            If Resto(2) <> 0 Then
               Kn = Resto(3)
            End If
         Incr Resto(3)
      Next Aux 1
   Next Cont1
   'in kn there is the significant bits
   'left justify the Numerador
   For Cont1 = 1 To 8
      Rot(cont1) = Numerador(cont1)
   Next Cont1
   Resto(1) = Kw - Kn
   For Cont2 = 1 To Resto(1)
      Call Leftshift()
   Next Cont2
   For Cont1 = 1 To 8
      Numerador(cont1) = Rot(cont1)
   Next Cont1
   'clear Resto() and Divisor()
   For Cont1 = 1 To 8
      Divisor(cont1) = 0
      Resto(cont1) = 0
   Next Cont1
   Index = Kn

   While Index > 0
      'decrement index
      Decr Index
      'rotate Numerador thru carry
      For Cont1 = 1 To 8
         Rot(cont1) = Numerador(cont1)
      Next Cont1
      Call Leftshift()
      For Cont1 = 1 To 8
         Numerador(cont1) = Rot(cont1)
      Next Cont1
      'rotate Resto thru carry
      For Cont1 = 1 To 8
         Rot(cont1) = Resto(cont1)
      Next Cont1
      Call Leftshift()
      For Cont1 = 1 To 8
         Resto(cont1) = Rot(cont1)
      Next Cont1
      'Subtract Denominador() from Resto() and put in res()
      For Cont1 = 1 To 8
         Restado(cont1) = Resto(cont1)
         Restando(cont1) = Denominador(cont1)
      Next Cont1
      Call Subtract()
      'complement carry
      If Carry = 0 Then
         Carry = 1
      Else
         Carry = 0
      End If
      'If carry = 1 then Resto = res
      If Carry = 1 Then
         For Cont1 = 1 To 8
            Resto(cont1) = Res(cont1)
         Next Cont1
      End If
      'rotate divisor thru carry
      For Cont1 = 1 To 8
         Rot(cont1) = Divisor(cont1)
      Next Cont1
      Call Leftshift()
      For Cont1 = 1 To 8
         Divisor(cont1) = Rot(cont1)
      Next Cont1
   Wend
End Sub







'****************************************************
' Subroutine to subtract restando from restado in
' 64 bits with zero if both are equal and carry 1 if
' the result Res is negative
'****************************************************
Sub Subtract()
   Zero = 1
   Aux1 = 0
   For Cont1 = 8 To 1 Step -1
      If Zero = 1 Then
         If Restado(cont1) <> Restando(cont1) Then
            Zero = 0
            If Restado(cont1) > Restando(cont1) Then
               Carry = 0
              Else
               Carry = 1
            End If
         End If
      End If
   Next Cont1
   If Zero = 0 Then
      If Carry = 1 Then
         For Cont1 = 1 To 8
            Swap Restado(cont1) , Restando(cont1)
         Next Cont1
      End If
      For Cont1 = 1 To 8
         Aux2 = Restando(cont1) + Aux1
         If Restado(cont1) < Aux2 Then
            Aux3 = 256 - Aux2
            Res(cont1) = Restado(cont1) + Aux3
            Aux1 = 1
         Else
            Res(cont1) = Restado(cont1) - Aux2
            Aux1 = 0
         End If
      Next Cont 1
   Else
      For Cont1 = 1 To 8
         Res(cont1) = 0
      Next Cont 1
      Carry = 0
   End If
End Sub

'****************************************************
' Subroutine to left shift thru Carry the 64 bits Rot
' carry should be 0 or 1
'****************************************************
Sub Leftshift()
   For Cont1 = 1 To 8
      If Rot(cont1) > 127 Then
         Aux1 = 1
      Else
         Aux1 = 0
      End If
      Shift Rot(cont1) , Left , 1
      Rot(cont1) = Rot(cont1) + Carry
      Carry = Aux1
   Next Cont1
End Sub

womai
Posts: 239
Joined: 16 Apr 2008 07:45

#5 Post by womai » 15 Dec 2008 16:11

Hi,

thanks for the code! I did this years ago but my code would be difficult to port, writing it from scratch would have been easier.

When I get to successfully port your code to MikroC I will post it here.

One short question to your code, there are some variables defined as basic types (int and long, i.e. I assume 2-byte and 4-byte integers). Will those need to change if I go from 8-byte calculations to 12-byte calculations? Or is all that is needed to basically replace all 8s in the code with 12s (loop limits, array sizes)?

Thanks,

Wolfgang

EC3AEL
Posts: 15
Joined: 11 Dec 2008 09:01

#6 Post by EC3AEL » 15 Dec 2008 16:14

I just made the code to be complain with the IEEE 64 bits long long integer. This will be usefull for other codes (o when AD strat to make DDS with > 48 bits)
Regards JORGE

EC3AEL
Posts: 15
Joined: 11 Dec 2008 09:01

#7 Post by EC3AEL » 15 Dec 2008 16:16

Hi again!
The intermediate calculus i used the minimum lenght that can store the intermediate values (to avoid deal with the internal CARRY bit) and use a virtual CARRY flag for the shift routines

Regards JORGE

womai
Posts: 239
Joined: 16 Apr 2008 07:45

#8 Post by womai » 16 Dec 2008 22:07

I converted the routines to MikroC and spent some time optimizing them for speed and memory. Runs now about 3x as fast as the converted original. I also cleaned up the code - all variables are local and the functions do not modify their input values, only the result values.

Still some things to do - the array indices are 1-based, which wastes a byte per value, need to make them zero based. Also, I need to make the routines usable for larger (>4 byte) numbers.

I plan to add functions to convert the numbers to/from decimal text strings, and implement an "add" function.

Anyway, as promised here is the converted code - hope it is useful!

Wolfgang

Code: Select all

#include <built_in.h>

//'*************************************
//' variables declare in the subroutines
//'*************************************

char val1[9];
char val2[9];
char val3[9];
char val4[9];
char rem[9];

//'*************************************
//' function prototypes
//'*************************************

void multiply(char* value1, char* value2, char* result);
void divide(char* value1, char* value2, char* result, char* remainder);
void subtract(char* value1, char* value2, char* result, char* carry);
void leftshift(char* value, char* carry);

void add(char* value1, char* value2, char* result);

void convert_dec_to_bin(char* dec_val, char* bin_val);
void convert_bin_to_dec(char* bin_val, char* dec_val);


//'****************************************************
//' calculates "value1 * value2" and stores result in "result"
//'****************************************************

void multiply(char* value1, char* value2, char* result)
{
   char i, j;
   unsigned long aux4;

   aux4 = 0;

   for (i = 1; i <= 8; i++)
   {
      for (j = i; j >= 1; j--)
      {
         aux4 = aux4 + value1[j] * value2[i + 1 - j];
      }

      result[i] = Lo(aux4);
      aux4 = aux4 >> 8;
   }
}


//'****************************************************
//' Calculates "value1 / value2"
//' stores result in "result" and remainder in "remainder"
//'****************************************************

void divide(char* value1, char* value2, char* result, char* remainder)
{
   char i;
   char aux1;
   char kn;
   char kw;
   char carry;
   char res[9];
   char value1_copy[9];

   kw = 64;
   carry = 0;

   // calculate kn number of significant bits in value1

   remainder[3] = 1;

   memcpy (value1_copy, value1, 9);

   for (i = 1; i <= 8; i++)
      for (aux1 = 0; aux1 <= 7; aux1++)
      {
            remainder[1] = 1 << aux1;
            remainder[2] = value1_copy[i] & remainder[1];
            
            if (remainder[2])
               kn = remainder[3];

            ++(remainder[3]);
      }

   // in kn there is the significant bits
   // left justify the value1_copy
   remainder[1] = kw - kn;
   
   for (i = 1; i <= remainder[1]; i++)
      leftshift(value1_copy, &carry);

   memset (result, 0, 9);
   memset (remainder, 0, 9);

   i = kn;

   while (i--)
   {
      leftshift(value1_copy, &carry);
      leftshift(remainder, &carry);

      subtract (remainder, value2, res, &carry);

      carry = carry ? 0 : 1;

      if (carry)
         memcpy (remainder, res, 9);

      leftshift(result, &carry);
   } // end while
}


//'****************************************************
//' calculates "value1 - value2", stores result in "result"
//' "carry" is 1 if result is negative
//'****************************************************

void subtract(char* value1, char* value2, char* result, char* carry)
{
   char i;
   char dummy;
   char aux1;
   char zero;
   unsigned int aux2;
   char value1_copy[9];
   char value2_copy[9];

   zero = 1;
   aux1 = 0;

   memcpy (value1_copy, value1, 9);
   memcpy (value2_copy, value2, 9);

   for (i = 8; i >= 1; i--)
   {
      if (zero)
      {
         if (value1_copy[i] != value2_copy[i])
         {
            zero = 0;
            
            *carry = (value1_copy[i] > value2_copy[i]) ? 0 : 1;
         }
      }
   }
   
   if (!zero)
   {
      if (*carry)
         for (i = 1; i <= 8; i++)
         {
            dummy = value1_copy[i];
            value1_copy[i] = value2_copy[i];
            value2_copy[i] = dummy;
         }

      for (i = 1; i <= 8; i++)
      {
         aux2 = value2_copy[i] + aux1;
         
         if (value1_copy[i] < aux2)
         {
            result[i] = value1_copy[i] + (256 - aux2);
            aux1 = 1;
         }
         else
         {
            result[i] = value1_copy[i] - aux2;
            aux1 = 0;
         }
      }
   }
   else
   {
      for (i = 1; i <= 8; i++)
         result[i] = 0;

      *carry = 0;
   }
}

//'****************************************************
//' Subroutine to left shift value with carry bit
//'****************************************************

void leftshift(char* value, char* carry)
{
   char i;
   char aux1;

   for (i = 1; i <= 8; i++)
   {
      aux1 = (value[i] > 127) ? 1 : 0;
      value[i] = (value[i] << 1) + (*carry);
      *carry = aux1;
   }
}

void main (void)
{
    char i;
    
    for (i = 1; i <= 8; i++)
        val3[i] = 0;

    val1[1] = 0x16;
    val1[2] = 0x25;
    val1[3] = 0x02;
    val1[4] = 0x88;
    val1[5] = 0;
    val1[6] = 0;
    val1[7] = 0;
    val1[8] = 0;
    val2[1] = 0x44;
    val2[2] = 0x55;
    val2[3] = 0x66;
    val2[4] = 0x77;
    val2[5] = 0;
    val2[6] = 0;
    val2[7] = 0;
    val2[8] = 0;

//    carry = 1;

    multiply(val1, val2, val3);
    divide(val3, val2, val4, rem); // should yield val1
    divide(val3, val1, val4, rem); // should yield val2
}

womai
Posts: 239
Joined: 16 Apr 2008 07:45

#9 Post by womai » 28 Dec 2008 10:27

Ok, I ended up rewriting the routines from scratch. The new routines work with numbers of arbitrary length (almost - since I restrict counters to char and signed char, the limit is 127 bytes, but that won't be an issue given the restricted memory space on a PIC :-) Just change the constant definition for the length. The array indexes are zero based so no RAM space gets wasted.

I did not yet have time to test the routines comprehensively, but I did do a number of spot checks. Feedback and bug reports are highly appreciated. I still need to implement conversion routines to and from text strings.

Performance is almost 10x faster than the routines posted above. My simulator says a division of two 8-byte numbers takes 20 msec or less (the larger the divisor, the faster; dividing by 1 is the worst case). Multiplication of two 8-byte numbers is around 2 msec. Addition and subtraction is around 0.1msec. All those numbers are on a PIC16F887; an 18F series PIC should be quite a bit faster because of its built-in hardware multiplier.

Note that the routines do no error checking whatsoever, so you need to make sure you don't get overflow etc. But none of the routines should ever modify its input parameters (important e.g. in order to assign the result to one of the input parameters) - let me know in case that happens anywhere.

Wolfgang

Here is the code:

Code: Select all

// APIM - Arbitrary Precision Integer Math
//
// Language: MikroC, for Microchip PIC
//
// arithmetic functions for positive integers of (almost) arbitrary length
// algorithms should work for up numbers consisting of up to 127 bytes
// note that no error checking is done (e.g. for overflow)

#include <built_in.h>
#define APIM_LENGTH 8 // size of numbers in bytes

// values are stored as array of char, LSB first, i.e.
// myvar[0] holds LSB, and myvar[APIM_LENGTH-1] holds MSB
void apim_add (char* oper1, char* oper2, char* result);
char apim_sub (char* oper1, char* oper2, char* result);
void apim_mult (char* oper1, char* oper2, char* result);
void apim_div (char* oper1, char* oper2, char* result, char* remainder);
void apim_inc (char* oper1);

signed char apim_compare(char* oper1, char* oper2);

void apim_shift_left_by_1 (char* oper);
void apim_shift_left_by_8N (char* oper, char n);
void apim_shift_left (char* oper, unsigned int shift_distance);
void apim_shift_right_by_1 (char* oper);

/* not implemented yet
  void apim_print_hex (char* val_bin, char* val_string);
  void apim_print_dec (char* val_bin, char* val_string);
  void apim_scan (char* val_string, char* val_bin);
*/

// calculates (oper1 + oper2)
void apim_add (char* oper1, char* oper2, char* result)
{
     char i;
     char carry;
     char oper2_copy;

     for (i = 0, carry = 0; i < APIM_LENGTH; i++)
     {
         oper2_copy = oper2[i]; // make a copy in case result and oper2 point to the same memory location
         carry = ((result[i] = oper1[i] + oper2_copy + carry) < oper2_copy) ? 1 : 0;
     }
}

// calculates (oper1 - oper2)
// returns 0 if result is positive, 1 if result is negative (negative result is unusable = incorrect)
char apim_sub (char* oper1, char* oper2, char* result)
{
     char i;
     char carry;
     char oper1_copy, oper2_copy;
     
     for (i = 0, carry = 0; i < APIM_LENGTH; i++)
     {
         oper1_copy = oper1[i]; // make a copy in case result and oper1 point to the same memory location
         oper2_copy = oper2[i]; // make a copy in case result and oper2 point to the same memory location
         result[i] = oper1_copy - oper2_copy - carry;
         carry = (oper1_copy >= (oper2_copy + carry)) ? 0 : 1;
     }
     
     return carry;
}

// calculates (oper1 * oper2)
void apim_mult (char* oper1, char* oper2, char* result)
{
     char i, j;
     char partial_prod[APIM_LENGTH];
     unsigned int byte_prod;
     char carry;
     
     memset (result, 0, APIM_LENGTH);

     for (i = 0; i < APIM_LENGTH; i++)
     {
         for (j = 0; j < APIM_LENGTH; j++)
         {
             byte_prod = oper1[j] * oper2[i] + carry;
             carry = hi (byte_prod);
             partial_prod[j] = lo (byte_prod);
         }
         
         apim_shift_left_by_8N (partial_prod, i);
         apim_add (result, partial_prod, result); // IMPORTANT: don't exchange result and partial_prod (will mess up apim_add)
     }
}

// calculates (oper1 / oper2)
void apim_div (char* oper1, char* oper2, char* result, char* remainder)
{
     char i, shift_counter;
     char oper2_copy[APIM_LENGTH];

     shift_counter = 0;

     memcpy (oper2_copy, oper2, APIM_LENGTH); // never modify input parameters!

     while (oper2_copy[APIM_LENGTH-1] == 0) // this will become an eternal loop if (oper2 == 0) (division by zero)
     {
           apim_shift_left_by_8N (oper2_copy, 1);
           shift_counter = shift_counter + 8;
     }
     
     while ((oper2_copy[APIM_LENGTH-1] & 0b10000000) == 0)
     {
           apim_shift_left_by_1 (oper2_copy);
           shift_counter++;
     }

     memcpy (remainder, oper1, APIM_LENGTH);
     memset (result, 0, APIM_LENGTH); // do after memcpy above, in case result and oper1 point to the same location

     for (i = 0; i <= shift_counter; i++)
     {
         apim_shift_left_by_1 (result);

         if (apim_compare (remainder, oper2_copy) >= 0)
         {
             apim_inc (result);
             apim_sub (remainder, oper2_copy, remainder);
         }
         
         apim_shift_right_by_1 (oper2_copy);
     }
}

// left-shifts oper by an arbitrary amount of bits
void apim_shift_left (char* oper, unsigned int n)
{
     char i;
     
     apim_shift_left_by_8N (oper, n >> 3);
     
     for (i = (n & 7); i > 0; i--)
     {
         apim_shift_left_by_1 (oper);
     }
}
     
// left-shifts oper in steps of full bytes (8 bits)
void apim_shift_left_by_8N (char* oper, char n)
{
     memmove (oper + n, oper, APIM_LENGTH - n);
     memset (oper, 0, n);
}

// left-shifts oper by one bit
void apim_shift_left_by_1 (char* oper)
{
     unsigned int i;
     char carry, carry_new;

     for (i = 0, carry = 0; i < APIM_LENGTH; i++)
     {
         carry_new = ((oper[i]) & 0b10000000) ? 1 : 0;
         oper[i] = (oper[i] << 1) + carry;
         carry = carry_new;
     }
}

// right-shifts oper by one bit
void apim_shift_right_by_1 (char* oper)
{
     signed int i;
     char carry, carry_new;

     for (i = APIM_LENGTH - 1, carry = 0; i >= 0; i--)
     {
         carry_new = (oper[i] & 0b00000001) ? 0b10000000 : 0;
         oper[i] = (oper[i] >> 1) + carry;
         carry = carry_new;
     }
}

// compares two numbers
// returns: 0 = numbers are equal, 1 = oper1 is larger, -1 = oper1 is smaller
signed char apim_compare(char* oper1, char* oper2)
{
     signed char i;
     
     i = APIM_LENGTH - 1;

     while ((oper1[i] == oper2[i]) && (i >= 0)) i--;
     
     if (i < 0)
     {
        return 0; // numbers are equal
     }
     else if (oper1 [i] > oper2 [i])
     {
         return 1; // oper1 is larger
     }
     else
     {
         return -1; // oper1 is smaller
     }
}

// increments oper1 by 1
void apim_inc (char* oper1) // increments oper1 by 1
{
     char i;
     char carry;
     unsigned int dummy;
     
     dummy = 1;
     
     for (i = 0; i < APIM_LENGTH; i++)
     {
         dummy = dummy + oper1[i];
         oper1[i] = lo(dummy);
         dummy = hi(dummy);
     }
}

char my_carry;

void main()
{
     char val1[APIM_LENGTH] = {0x19,0x28,0x37,0x46,0x00,0x00,0x00,0x00};
     char val2[APIM_LENGTH] = {0xff,0x11,0xee,0x66,0x00,0x00,0x00,0x00};
     char res[APIM_LENGTH] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
     char resdiv[APIM_LENGTH] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
     char rem[APIM_LENGTH] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
     char one[APIM_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
     char onetofour[APIM_LENGTH] = {0x01,0x02,0x03,0x04,0x00,0x00,0x00,0x00};

     apim_mult (val1, val2, res);
     apim_div (res, val1, resdiv, rem); // should yield val2
     apim_div (res, val2, resdiv, rem); // should yield val1
     apim_div (res, one, resdiv, rem); // should yield res
     apim_inc (res);
     apim_div (res, val2, resdiv, rem); // should yield val1 and rem=1
     apim_add (res, onetofour, res);
     apim_div (res, val2, resdiv, rem); // should yield val1 and rem=04 03 02 02

     my_carry = apim_sub (val1, val2, res);
     my_carry = apim_sub (val2, val1, res);

     apim_mult (val1, val2, res);
     apim_mult (val2, val1, res);

     apim_shift_left (val1,13);
     apim_shift_left_by_1 (val1);
     apim_shift_left_by_1 (val1);
     apim_shift_left_by_1 (val1); // should yield original val1 shifted by 2 bytes
}

luttappy
Posts: 1
Joined: 08 Feb 2009 11:42

#10 Post by luttappy » 08 Feb 2009 12:02

Hi sir.

w r t the post under "How to calculate with 32 Bit variables => 64 Bit needed"

i was not able to find the logic behind the add_apim function.

According to ur logic

If for eg: LENGTH=4

03FFFF08 +
01555555

will yield 0455545D rather than 0555545D

It can be corrected by knowing the carry flag in the STATUS REGISTER using Assembly...

Also let me kno if there is any way to acccess the CARRY flag using MikroC...



With Regards
Luttappy

womai
Posts: 239
Joined: 16 Apr 2008 07:45

#11 Post by womai » 08 Feb 2009 19:45

Hi luttappy,

thanks for alerting me to this behavior! - it is indeed a bug in my code that happens whenever operand 2's byte is 0xff and carry is 1. I fixed the code, below is the corrected apim_add function. I checked and your example now produces the expected result.

Wolfgang

Code: Select all

// calculates (oper1 + oper2)
void apim_add (char* oper1, char* oper2, char* result)
{
     char i;
     char carry;
     char oper2_copy;
     unsigned int res;
     
     for (i = 0, carry = 0; i < APIM_LENGTH; i++)
     {
         oper2_copy = oper2[i]; // make a copy in case result and oper2 point to the same memory location
         res = oper1[i] + oper2_copy + carry;
         result[i] = lo(res);
         carry = hi(res);
     }
}

Post Reply

Return to “mikroC General”