0
votes

I have a 14-bit data that is fed from FPGA in vhdl, The NIos II processor reads the 14-bit data from FPGA and do some processing tasks, where Nios II system is programmed in C code

The 14-bit data can be positive, zero or negative. In Altera compiler, I can only define the data to be 8,16 or 32. So I define this to be 16 bit data.

First, I need to check if the data is negative, if it is negative, I need to pad the first two MSB to be bit '1' so the system detects it as negative value instead of positive value.

Second, I need to compute the real value of this binary representation into a decimal value of BOTH integer and fraction.

I learned from this link (Correct algorithm to convert binary floating point "1101.11" into decimal (13.75)?) that I could convert a binary (consists of both integer and fraction) to decimal values.

To be specified, I am able to use this code quoted from this link (Correct algorithm to convert binary floating point "1101.11" into decimal (13.75)?) , reproduced as below:

#include <stdio.h>
#include <math.h>

double convert(const char binary[]){
  int bi,i;
  int len = 0;
  int dot = -1;
  double result = 0;

  for(bi = 0; binary[bi] != '\0'; bi++){
    if(binary[bi] == '.'){
      dot = bi;
    }
    len++;
  }
  if(dot == -1)
    dot=len;

  for(i = dot; i >= 0 ; i--){
    if (binary[i] == '1'){
      result += (double) pow(2,(dot-i-1));
    }
  }
  for(i=dot; binary[i] != '\0'; i++){
    if (binary[i] == '1'){
      result += 1.0/(double) pow(2.0,(double)(i-dot));
    }
  }
  return result;
}

int main()
{
   char  bin[] = "1101.11";
   char  bin1[] = "1101";
   char  bin2[] = "1101.";
   char  bin3[] = ".11";

   printf("%s -> %f\n",bin, convert(bin)); 
   printf("%s -> %f\n",bin1, convert(bin1)); 
   printf("%s -> %f\n",bin2, convert(bin2)); 
   printf("%s -> %f\n",bin3, convert(bin3)); 

   return 0;
}

I am wondering if this code can be used to check for negative value? I did try with a binary string of 11111101.11 and it gives the output of 253.75...

I have two questions:

  1. What are the modifications I need to do in order to read a negative value?

I know that I can do the bit shift (as below) to check if the msb is 1, if it is 1, I know it is negative value...

if (14bit_data & 0x2000) //if true, it is negative value

The issue is, since it involves fraction part (but not only integer), it confused me a bit if the method still works...

  1. If the binary number is originally not in string format, is there any way I could convert it to string? The binary number is originally fed from a fpga block written in VHDL say, 14 bits, with msb as the sign bit, the following 6 bits are the magnitude for integer and the last 6 bits are the magnitude for fractional part. I need the decimal value in C code for Altera Nios II processor.
2
You mention FPGA. In which langage are you writing you code ? VHDL ? VLOG ? or is it software code written in C by example ?Quicky
@Quicky, thanks for your reply, sorry for not making it clear, it is vhdl in fpga and C code in Altera Nios II system (will edit it in the main post for clarification)user2563812
But here you question concern C code ? I don`t understand what is you question exactly ? Do you just want to check if this is a negative value ? or compute the real value of this binary represenation assuming this is a signed number ?Quicky
The 14-bit data is fed from FPGA in vhdl, the NIos II processor reads the 14-bit data from FPGA and do some processing tasks, where Nios II system is programmed in C codeuser2563812
Ok that's clear. And so what is the goal of the code ?Quicky

2 Answers

2
votes

OK so I m focusing on the fact that you want to reuse the algorithm you mention at the beginning of your question and assume that the binary representation you have for your signed number is Two's complement but I`m not really sure according to your comments that the input you have is the same than the one used by the algorithm

First pad the 2 MSB to have a 16 bit representation

16bit_data = (14_bit_data & 0x2000) ? ( 14_bit_data | 0xC000) : 14_bit_data ;

In case value is positive then value will remained unchanged and if negative this will be the correct two`s complement representation on 16bits.

For fractionnal part everything is the same compared to algorithm you mentionned in your question.
For integer part everything is the same except the treatment of MSB.
For unsigned number MSB (ie bit[15]) represents pow(2,15-6) ( 6 is the width of frationnal part ) whereas for signed number in Two`s complement representation it represents -pow(2,15-6) meaning that algorithm become

/* integer part operation */    
while(p >= 1)
{
  rem = (int)fmod(p, 10);
  p = (int)(p / 10);
  dec = dec + rem * pow(2, t) * (9 != t ? 1 : -1);
  ++t;
}

or said differently if you don`t want * operator

/* integer part operation */    
while(p >= 1)
{
  rem = (int)fmod(p, 10);
  p = (int)(p / 10);
  if( 9 != t)
  {
     dec = dec + rem * pow(2, t);
  }
  else
  {
     dec = dec - rem * pow(2, t);
  }
  ++t;
}

For the second algorithm that you mention, considering you format if dot == 11 and i == 0 we are at MSB ( 10 integer bits followed by dot) so the code become

for(i = dot - 1; i >= 0 ; i--)
{
   if (binary[i] == '1')
   {
       if(11 != dot || i)
       {
           result += (double) pow(2,(dot-i-1));
       }
       else
       {
           // result -= (double) pow(2,(dot-i-1));
           // Due to your number format i == 0 and dot == 11 so
          result -= 512
       }
   }
}

WARNING : in brice algorithm the input is character string like "11011.101" whereas according to your description you have an integer input so I`m not sure that this algorithm is suited to your case

1
votes

I think this should work:

float convert14BitsToFloat(int16_t in)
{
    /* Sign-extend in, since it is 14 bits */
    if (in & 0x2000) in |= 0xC000;

    /* convert to float with 6 decimal places (64 = 2^6) */
    return (float)in / 64.0f;
}

To convert any number to string, I would use sprintf. Be aware it may significantly increase the size of your application. If you don't need the float and what to keep a small application, you should make your own conversion function.