将二进制(整数和分数)从VHDL转换为C代码中的十进制,负值

时间:2015-05-28 11:51:55

标签: string binary fpga signed

我有一个从vhdl中的FPGA馈送的14位数据,NIos II处理器从FPGA读取14位数据并执行一些处理任务,其中Nios II系统用C代码编程

14位数据可以是正数,零或负数。在Altera编译器中,我只能将数据定义为8,16或32.所以我将其定义为16位数据。

首先,我需要检查数据是否为负数,如果是负数,我需要将前两个MSB填充为位'1',以便系统将其检测为负值而不是正值。

其次,我需要将这个二进制表示的实际值计算为BOTH整数和分数的十进制值。

我从这个链接(Correct algorithm to convert binary floating point "1101.11" into decimal (13.75)?)中了解到,我可以将二进制(由整数和分数组成)转换为十进制值。

要指定,我可以使用此链接引用的代码(Correct algorithm to convert binary floating point "1101.11" into decimal (13.75)?),如下所示:

#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;
}

我想知道这段代码是否可用于检查负值?我尝试使用二进制字符串11111101.11,它输出253.75 ...

我有两个问题:

  1. 为了读取负值,我需要做哪些修改?
  2. 我知道我可以进行位移(如下所示)来检查msb是否为1,如果是1,我知道它是负值......

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

    问题是,因为它涉及小数部分(但不仅仅是整数),如果方法仍然有效,它会让我感到困惑......

    1. 如果二进制数最初不是字符串格式,有什么办法可以将它转换为字符串吗?二进制数最初来自用VHDL编写的fpga块,例如14位,msb作为符号位,后面的6位是整数的幅度,后6位是小数部分的幅度。我需要Altera Nios II处理器的C代码中的十进制值。

2 个答案:

答案 0 :(得分:2)

好的,所以我专注于你想要重复使用你在问题开头提到的算法的事实,并假设你签名的数字的二进制表示是Two's complement但是我根据你的意见,我不确定你的输入是否与算法使用的输入相同

首先填充2 MSB以具有16位表示

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

如果值为正,则值将保持不变,如果为负,则这将是16位上正确的二进制补码表示。

对于分数部分,与您在问题中提到的算法相比,一切都是相同的 对于整数部分,除了MSB的处理外,一切都是相同的 对于无符号数,MSB(即位[15])表示pow(2,15-6)(6是frationnal部分的宽度),而对于2的补码表示中的带符号数,它表示-pow(2,15-6)意思是算法成为

/* 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;
}

或者如果你不想要*运营商

则说不同
/* 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;
}

对于你提到的第二个算法,考虑到格式化如果dot == 11和i == 0我们是MSB(10个整数位后跟点)所以代码变为

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
       }
   }
}

警告:在brice算法中,输入是字符串,如“11011.101”,而根据您的描述,您有一个整数输入,因此我不确定此算法是否适合您的情况

答案 1 :(得分:1)

我认为这应该有效:

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;
}

要将任何数字转换为字符串,我会使用sprintf。请注意,它可能会显着增加您的应用程序的大小。如果您不需要浮动以及保留小型应用程序的内容,则应该创建自己的转换函数。