/*
dapkg_gen modified to accept negative and fractional coefficients
James Edgar July 2004
jamessedgar@hotmail.com

*/
/* dapkg_gen -- Distributed Arithmetic package generator
* Copyright (C) 2000 Jamil Khatib
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/* This program generates the DApkg.vhd file that is used to define
* the DA filter core and gives its parameters and the contents of the
* Distributed Arithmetic Look-up-table "DALUT" according to the DA algorithm
*/

/*
*
* To compile the program do: gcc -o DApkg_gen DApkg_gen.c
*
*/

/*  INCLUDES */
#include <stdio.h>
#include <stdlib.h>



/*  DEFINES  */

#define MAXTAPS 64		 		/* Maximum number of taps */
#define MAXWORDSIZE 64   		/* Maximum word size      */
#define MAXROMSIZE pow2(MAXTAPS)/* Maximum ROM size	      */



void tobinstr(unsigned int ,unsigned int ,char * );
void try_again(int * i);
unsigned int pow2(unsigned int );

void generate_LUT(unsigned int [] , unsigned int []  ,unsigned int, unsigned 
int word_size );


/* Main function */

main(int argc,char **argv)
{

  float	float_coef;
  unsigned int total_bits;
  unsigned int fract_bits;
  unsigned int taps = 0;
  unsigned int word_size = 0;
  unsigned char signs[16];
  unsigned int constants[16]; //[MAXTAPS];

  unsigned int constants_table[65536]; //[MAXROMSIZE];

  char binary_num[65539]; //[MAXWORDSIZE+3];

  unsigned int rom_size = 0;

  unsigned int i =0;
  unsigned char negatives=0;

  FILE * f;

  printf("\n*********DApkg.vhd generator**********\n");

  i=0;
  while (i==0)
  {
	i++;
    printf("\nEnter no. of filter taps ");
    scanf("%d",&taps);
    if( taps <= 0 )
	{
      printf("Negative numbers are not allowed\n");
	  try_again(&i);
    }
  }

  rom_size = pow2(taps); /* Calculate rom size */

  i=0;
  while (i==0)
  {
	i++;
	printf("\nEnter total number of bits in coefficients (include 1 for sign if 
needed) ");
	scanf("%d",&total_bits);
    if( total_bits <= 0 )
    {
      printf("Negative numbers are not allowed\n");
	  try_again(&i);

    }
    if( total_bits > 32 )
    {
	  int i;
      printf("Too many bits -- modify da_package if more bits desired\n");
	  try_again(&i);
    }

  }


  i=0;
  while (i==0)
  {
	i++;
  printf("\nEnter number of bits in coefficient fractions ");
  scanf("%d",&fract_bits);

   if( fract_bits < 0 )
    {
      printf("Negative numbers are not allowed\n");
	  try_again(&i);

    }
    if( fract_bits > total_bits )
    {
      printf("Too many bits -- Fractional bits must be <= total bits\n");
	  try_again(&i);

    }
  }
  {
	 int j=0;
	 while (j==0)
	 {
		 j++;
	     printf("\nEnter filter constants starting from tap[0]");

		 i=0;
		 for(i=0;i < taps;i++)
	     {
			int ok=0;
			int temp;
			printf("\n[%d]:",i);
			scanf("%f",&float_coef);
			if (float_coef < 0)
			{
				 negatives=1;
	 			 signs[i]=1;
				 float_coef = -float_coef*pow2(fract_bits)+1;
				 temp = (int)float_coef;
				 if (temp>pow2(total_bits-1)-1)
				 {
					ok=1;
					printf("[Error]: Negative number < %d with %d integer bits 
\n",-pow2(total_bits-fract_bits-1)+1,total_bits-fract_bits-1);
					try_again(&i);
				 }
				 temp = -temp+pow2(total_bits)+1;
			}
			else
			{
				 signs[i]=0;
				 float_coef = float_coef*pow2(fract_bits);
				 temp = (int)float_coef;
				 if (temp>pow2(total_bits)-1)
				 {
					ok=1;
					printf("[Error]: positive number > %d with %d integer bits 
\n",pow2(total_bits-fract_bits)-1,total_bits-fract_bits);
					try_again(&i);
				 }
			 }
			if (ok==0)
			{
				constants[i]=temp;
				//printf(" float_coef %f constants[i] %d \n",float_coef,constants[i]);
			}

       }
	// recheck positive coefficients if negative coefficients exist
		if (negatives==1)
		{
		   int k=0;
		   while (k<taps)
		   {
			   if (signs[k]==0)
			   {
				 if (constants[k]>pow2(total_bits-1)-1)
				 {
					printf("Negative coefficients detected -- integer bits = %d 
\n",total_bits-fract_bits-1);
					printf(" Coefficient %d = %d \n",k,constants[k]);
					printf("[Error]: positive number > %d with %d integer bits 
\n",pow2(total_bits-fract_bits-1)-1,total_bits-fract_bits-1);
					try_again(&j);
					k=taps;
				 }
			   }
			   k++;
		   }
		}
	 }
  }

  printf("\nFilter information\n");
  printf("\nFilter taps = [%d]",taps);
  printf("\nWord size = [%d]",word_size);
  printf("\nFilter constants\n");

  for( i =0; i< taps; i++)
  {
    printf("\n[%d]:[%d]",i,constants[i]);

  }

  printf("\n");

  printf("\nLUT contents\n");
  // Calculate max word size
  {
  unsigned int total_neg=0, total_pos=0, total_max=0;
  i=0;
  while (i<taps)
  {
	 if (negatives==1)
	  if (constants[i]<(pow2(total_bits-1)))
		total_pos=total_pos+constants[i];
	  else
	    total_neg=total_neg+constants[i];
	  else
		  total_pos=total_pos+constants[i];
	i++;
  }
  if (total_pos>total_neg)
	  total_max=total_pos;
  else
	  total_max=total_neg;
  word_size=total_bits;
  while (pow2(word_size)<total_max)
	  word_size++;
  printf("Word size will be %d for largest sum of %d (all positives or all 
negatives)\n",word_size,total_max);
  }
  // fix negative numbers to match word size
  if (negatives==1)
  {
	int fix_neg;
	fix_neg=pow2(word_size)-pow2(total_bits);
	i=0;
	while (i<taps)
	{
	  if (negatives==1)
	  if (constants[i]>=(pow2(total_bits-1)))
		constants[i]=constants[i]+fix_neg;
	  i++;
	}
  }

/* Calculate LUT contents */
  generate_LUT(constants, constants_table, taps, word_size);

  f = fopen("DApkg.vhd","w+");

fprintf(f,"-------------------------------------------------------------------------------\n");
fprintf(f,"-- Title      :Distributed Arithmetic Package\n");
fprintf(f,"-- Project    : Arithmetic blocks\n");
fprintf(f,"-------------------------------------------------------------------------------\n");
fprintf(f,"	 -- File        : DApkg.VHD\n");
fprintf(f,"-- Author      : Jamil Khatib  \n");
fprintf(f,"-- Organization: OpenIPCore Project\n");
fprintf(f,"-- Created     : 2000/04/17\n");
fprintf(f,"-- Last update : 2000/04/17\n");
fprintf(f,"-- Platform    : \n");
fprintf(f,"-- Simulators  : Modelsim 5.3XE / Windows98\n");
fprintf(f,"-- Synthesizers: Leonardo / WindowsNT\n");
fprintf(f,"-- Target      : \n");
fprintf(f,"-- Dependency  : \n");
fprintf(f,"------------------------------------------------------------------------------\n");
fprintf(f,"-- Description: Distributed Arithmetic Package\n");
fprintf(f,"------------------------------------------------------------------------------\n");
fprintf(f,"-- Copyright (c) 2000 Jamil Khatib\n");
fprintf(f,"-- \n");
fprintf(f,"-- This VHDL design file is an open design; you can redistribute 
it and/or\n");
fprintf(f,"-- modify it and/or implement it under the terms of the Openip 
General Public\n");
fprintf(f,"-- License as it is going to be published by the OpenIPCore 
Organization and\n");
fprintf(f,"-- any coming versions of this license.\n");
fprintf(f,"-- You can check the draft license at\n");
fprintf(f,"-- http://www.opencores.org/OIPC/license.html\n");
fprintf(f,"\n");
fprintf(f,"------------------------------------------------------------------------------\n");
fprintf(f,"-- Revisions  :\n");
fprintf(f,"-- Revision Number :   \n");
fprintf(f,"-- Version         :   0.1\n");
fprintf(f,"-- Date            :   17th Apr 2000\n");
fprintf(f,"-- Modifier        :   Jamil Khatib (khatib@ieee.org)\n");
fprintf(f,"-- Desccription    :   Created\n");
fprintf(f,"--\n");
fprintf(f,"-------------------------------------------------------------------------------\n");
fprintf(f,"-- Revisions  :\n");
fprintf(f,"-- Revision Number :   2\n");
fprintf(f,"-- Version         :   0.2\n");
fprintf(f,"-- Date            :   30h Apr 2000\n");
fprintf(f,"-- Modifier        :   Jamil Khatib (khatib@ieee.org)\n");
fprintf(f,"-- Desccription    :   defining the constant CONSTANTS for DALUT 
contents\n");
fprintf(f,"--					   which should be genrated automatically in later 
versions\n");
fprintf(f,"--\n");
fprintf(f,"-------------------------------------------------------------------------------\n");
fprintf(f,"\n");
fprintf(f,"-- This file was generated by DApkg_gen binary tool\n");
fprintf(f,"\n");
fprintf(f,"library ieee;\n");
fprintf(f,"use ieee.std_logic_1164.all;\n");
fprintf(f,"\n");
fprintf(f," package DApkg is\n");
fprintf(f,"  constant BUFFER_SIZE : integer := %d;  -- No. of inputs, No of 
filter taps,\n",taps);
fprintf(f,"                                        -- No. of constants , 
Buffer Size\n");
fprintf(f,"  constant DATA_SIZE   : integer := %d;  -- Word 
size\n",word_size);
fprintf(f,"\n");
fprintf(f,"  type TABLE is array ( 0 to (2**BUFFER_SIZE) -1) of 
std_logic_vector((DATA_SIZE -1 ) downto 0);\n");
fprintf(f,"                                        -- Memory type\n");
fprintf(f," constant CONSTANTS : TABLE := (\n\n");


/**************************************/

/* write the LUT contents into the file */
for(i = 0; i < rom_size-1 ;i++)
{

     tobinstr(constants_table[i],word_size,binary_num);
     printf("\nDALUT[%d] = [%d]   %sb",i,constants_table[i],binary_num);
     fprintf(f,"   %s,\n",binary_num);

}


tobinstr(constants_table[i],word_size,binary_num);
printf("\nDALUT[%d] = [%d]   %sb",i,constants_table[i],binary_num);
fprintf(f,"   %s\n",binary_num);

/************************************/

fprintf(f,"\n);\n-------------------------------------------------------------------------------\n");
fprintf(f,"-- DA filter top core\n");
fprintf(f,"\n");
fprintf(f,"  component DA\n");
fprintf(f,"    generic (\n");
fprintf(f,"      NOINPUTS  :     integer := BUFFER_SIZE;  -- number of 
inputs, no. of filter taps\n");
fprintf(f,"      WORD_SIZE :     integer := DATA_SIZE;  -- word size\n");
fprintf(f,"      CONTENTS  :     TABLE   := CONSTANTS);\n");
fprintf(f,"    port (\n");
fprintf(f,"      data      : in  std_logic_vector(WORD_SIZE -1 downto 0);  
-- input data\n");
fprintf(f,"      Clk       : in  std_logic;        -- system clock\n");
fprintf(f,"      Rst_n     : in  std_logic;        -- System reset\n");
fprintf(f,"      Result    : out std_logic_vector(WORD_SIZE -1 downto 0);  
-- Result\n");
fprintf(f,"      ValidOut  : out std_logic;        -- Output valid\n");
fprintf(f,"      Overflow  : out std_logic);       -- Overflow signal\n");
fprintf(f,"  end component;\n");
fprintf(f,"------------------------------------------------------------------------------\n");
fprintf(f,"-- DALUT Distributed Arithmetic Lookup table\n");
fprintf(f,"\n");
fprintf(f," component DALUT\n");
fprintf(f,"    generic (\n");
fprintf(f,"      ADDR_SIZE   : integer;                   --:= 
BUFFER_SIZE;\n");
fprintf(f,"      -- LUT address size or number of input terms\n");
fprintf(f,"      OUTPUT_SIZE : integer;  --:= DATA_SIZE;  -- Output 
size\n");
fprintf(f,"      CONTENTS    : TABLE                      -- CONSTANTS\n");
fprintf(f,"      -- These values should be generated automaticlly from the 
original\n");
fprintf(f,"      -- constants of the filter\n");
fprintf(f,"  \n");
fprintf(f,"	  );\n");
fprintf(f,"  \n");
fprintf(f,"    port (\n");
fprintf(f,"      Address : in  std_logic_vector(ADDR_SIZE -1 downto 0);  -- 
DALUT Address\n");
fprintf(f,"      Result  : out std_logic_vector(OUTPUT_SIZE -1 downto 0));  
-- Result\n");
fprintf(f,"\n");
fprintf(f,"  end component;\n");
fprintf(f,"\n");
fprintf(f,"  
-------------------------------------------------------------------------------\n");
fprintf(f,"\n");
fprintf(f,"end DApkg;\n");
fprintf(f,"package body DApkg is\n");
fprintf(f,"\n");
fprintf(f,"end DApkg;");
fprintf(f," \n");
fclose(f);

  printf("\nDApkg.vhd is generated\n");




  return 0;

}

/******************************************************************
* void tobinstr(unsigned int num,unsigned int size,char * str)
*
* tobinary converts from number to binary representation string
*
* Inputs:
* num : the number to be converted
* size: number of bits in the binary number
* str: string buffer to store the converted number
******************************************************************/

void tobinstr(unsigned int num,unsigned int size,char * str)
{
  unsigned int i = size;

  unsigned int tmp =0;

  str[0] = '"';
  str[size +1] = '"';
  str[size+2] = 0 ; //NULL;

  for (i=size; i > 0 ; i--)
    {

	 tmp = num & 0x1;


     switch(tmp)
     {
       case 0:
           str[i] = '0';
           break;
         case 1:
             str[i] = '1';
             break;
         default :
             printf("\n!!!!!!!!! Illegal number conversion !!!!!!!!!!\n");
             exit(1);

	 }


      num = num >> 1;

    }


  return ;

}


/******************************************************************
* unsigned int pow2(unsigned int num)
*
* pow2  calculates 2^num
*
* Inputs:
* num : the power
******************************************************************/

unsigned int pow2(unsigned int num)
{
    unsigned int res = 1;
    unsigned int i=0;

    for(i = 0; i < num; i++)
    {
        res = 2 * res;


    }
    return res;

}


/******************************************************************
* void generate_LUT(unsigned int  consts[], unsigned int  rom[],unsigned int 
num_const)
*
* Generates the LUT (rom) contents
*
* Inputs:
* consts[] : Filter's constants
* rom[]    : Array to store the LUT constants
* num_const: Number of filter's constants
*
******************************************************************/

void generate_LUT(unsigned int  consts[], unsigned int  rom[],unsigned int 
num_const, unsigned int word_size)
{

    unsigned int i= 0;
    unsigned int j = 0;
    unsigned int max_addr = pow2(num_const);
    unsigned int flag = 0;
    unsigned index = 0;


    for (i= 0;i < max_addr; i++)/* i = rom address*/
    {
        index = i;
        rom[i] = 0;

        for (j = 0; j < num_const; j++)
        {
            flag = 0x1 & index;  /* Mask the first bit*/

            rom[i] = rom [i] + ( consts[j] * flag);

            index >>=1; /* get next bit in the address*/
        }
		// remove bits above word size
		rom[i]=rom[i]%pow2(word_size);
    }


    return ;
}

void try_again(int * i)
{
	char yorn;
	printf("\nTry Again? ");
	scanf("%1s",&yorn);
	if (yorn=='y' | yorn=='Y')
		*i=*i-1;
	else
		exit(1);

	return;
}
