#!/usr/bin/python

# This file is part of the Coriolis Project.
# Copyright (C) Laboratoire LIP6 - Departement ASIM
# Universite Pierre et Marie Curie
#
# Main contributors :
#        Christophe Alexandre   <Christophe.Alexandre@lip6.fr>
#        Sophie Belloeil             <Sophie.Belloeil@lip6.fr>
#        Hugo Clement                   <Hugo.Clement@lip6.fr>
#        Jean-Paul Chaput           <Jean-Paul.Chaput@lip6.fr>
#        Damien Dupuis                 <Damien.Dupuis@lip6.fr>
#        Christian Masson           <Christian.Masson@lip6.fr>
#        Marek Sroka                     <Marek.Sroka@lip6.fr>
# 
# The  Coriolis Project  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.
# 
# The  Coriolis Project 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 the Coriolis Project;  if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
# License-Tag
# Authors-Tag
# ===================================================================
#
# x-----------------------------------------------------------------x 
# |                                                                 |
# |                   C O R I O L I S                               |
# |    S t r a t u s   -  Netlists/Layouts Description              |
# |                                                                 |
# |  Author      :                    Sophie BELLOEIL               |
# |  E-mail      :       Sophie.Belloeil@asim.lip6.fr               |
# | =============================================================== |
# |  Py Module   :       "./dpgen_ADSB2F.py"                        |
# | *************************************************************** |
# |  U p d a t e s                                                  |
# |                                                                 |
# x-----------------------------------------------------------------x



from stratus import *

class DpgenAdsb2f ( Model ) :

  ## Interface ##
  ###############
  def Interface ( self ) :
    global add_sub, c30, c31, i0, i1, q, vdd, vss

    self._nbit = self._param['nbit']

    add_sub = SignalIn  ( "add_sub",    1 )
    c30     = SignalOut (     "c30",    1 )
    c31     = SignalOut (     "c31",    1 )
    
    i0      = SignalIn  (      "i0", self._nbit )
    i1      = SignalIn  (      "i1", self._nbit )
    q       = SignalOut (       "q", self._nbit )

    vdd     = VddIn    ( "vdd" )
    vss     = VssIn    ( "vss" )
    
  ## Netlist ##
  #############
  def Netlist ( self ) :

    # Liste des signaux internes
    xorb = Signal ( "xorb", self._nbit )
    c    = Signal (    "c", self._nbit )
    
    pi   = []
    gi   = []
    for i in range ( self._nbit ) :
      pi_bis = []
      gi_bis = []
      for j in range ( self._nbit ) :
        pi_bis += [Signal("pi_%d_%d" % (i, j), 1 )]
        gi_bis += [Signal("gi_%d_%d" % (i, j), 1 )]
      pi += [pi_bis]
      gi += [gi_bis]

    c30.Alias ( c[self._nbit-2] )
    c31.Alias ( c[self._nbit-1] )

    # Ligne des XOR
    self.Xorb = {}
    for i in range ( self._nbit ) :
      self.Xorb[i] =  Inst ( "xr2_x1"
                           , "xorb%d" % i
                           , map = { 'i0'  : add_sub
                                   , 'i1'  : i1[i]
                                   , 'q'   : xorb[i]
                                   , 'vdd' : vdd
                                   , 'vss' : vss
                                   }
                           )

    # Ligne des PIGI
    self.Pigi = {}
    for i in range ( 1, self._nbit ) :
      self.Pigi[i] =  Inst ( "halfadder_x2"
                           , "pigi%d" % i
                           , map = { 'a'    : i0[i]
                                   , 'b'    : xorb[i]
                                   , 'cout' : gi[0][i]
                                   , 'sout' : pi[0][i]
                                   , 'vdd' : vdd
                                   , 'vss' : vss
                                   }
                           )
  
    # Ligne des PG
    self.PgI1 = {}
    self.PgI2 = {}
    
    for n in range ( 1, ilog2(self._nbit) + 1 ) :
        
      self.I1Bis = {}
      self.I2Bis = {}
      
      for ipg in range ( iexp2(n) + iexp2(n-1), self._nbit, iexp2(n) ) :
        inpg = ipg

        for npg in range ( iexp2(n-1) ) :
          if inpg >= self._nbit : break
          
          self.I1Bis[inpg] = Inst ( "a2_x2"
                                  , "pg_i1_%d_%d" % ( n, inpg )
                                  , map = { 'i0'  : pi[n-1][ipg-1]
                                          , 'i1'  : pi[ilog2(npg)][inpg ]
                                          , 'q'   : pi[n][inpg ]
                                          , 'vdd' : vdd
                                          , 'vss' : vss
                                          }
                                  )
          
          self.I2Bis[inpg] = Inst ( "oa22_x2"
                                  , "pg_i2_%d_%d" % ( n, inpg )
                                  , map = { 'i0' : pi[ilog2(npg)][inpg ]
                                          , 'i1' : gi[n-1       ][ipg-1]
                                          , 'i2' : gi[ilog2(npg)][inpg ]
                                          , 'q'  : gi[n         ][inpg ]
                                          , 'vdd' : vdd
                                          , 'vss' : vss
                                          }
                                  )
          
          inpg += 1

      self.PgI1[n] = self.I1Bis
      self.PgI2[n] = self.I2Bis
          
    # Calcul des retenues
    p = 2
    self.R = {}
    for n in range ( 1, ilog2 ( self._nbit ) + 1 ) :
      for isr in range ( iexp2 ( n - 1 ) ) :
        if iexp2 ( n - 1 ) + isr >= self._nbit : break
     
        self.R[p] = Inst ( "oa22_x2"
                         , "r%d" % p
                         , map = { 'i0' : pi[ilog2(isr)][iexp2(n-1) + isr]
                                 , 'i1' : c[iexp2(n-1) - 1]
                                 , 'i2' : gi[ilog2(isr)][iexp2(n-1) + isr]
                                 , 'q'  : c[iexp2(n-1) + isr]
                                 , 'vdd' : vdd
                                 , 'vss' : vss
                                 }
                         )
        p += 1
    
        
    # Calcul des sommes
    self.S = {}

    for i in range ( 1, self._nbit ) :
      self.S[i] = Inst ( "xr2_x1"
                       , "s%d"  % i
                       , map = { 'i0' : pi[0][i]
                               , 'i1' : c[i-1]
                               , 'q'  : q[i]
                               , 'vdd' : vdd
                               , 'vss' : vss
                               }
                       )
    
    # Calcul somme et retenue du LSB
    self.S[0] =  Inst ( "fulladder_x2"
                      , "s0"
                      , map = { 'a1'   : i0[0]
                              , 'a2'   : i0[0]
                              , 'a3'   : i0[0]
                              , 'a4'   : i0[0]
                              , 'b1'   : xorb[0]
                              , 'b2'   : xorb[0]
                              , 'b3'   : xorb[0]
                              , 'b4'   : xorb[0]
                              , 'cin1' : add_sub
                              , 'cin2' : add_sub
                              , 'cin3' : add_sub
                              , 'cout' : c[0]
                              , 'sout' : q[0]
                              , 'vdd' : vdd
                              , 'vss' : vss
                              }
                      )


  ## Layout ##
  ############
  def Layout ( self ) :

    twostage = -1
  
    # Ligne des XOR
    Place ( self.Xorb[0], NOSYM, XY ( 0, 0 ) )
    
    for i in range ( 1, self._nbit ) :
      if i % 2 == 0 : sym = NOSYM
      else          : sym = SYM_Y
      PlaceTop ( self.Xorb[i], sym )
       
    # Ligne des PIGI
    if self._nbit > 1 : Place ( self.Pigi[1], SYM_Y, XY ( 45, 50 ) )
    
    for i in range ( 2, self._nbit ) :
      if i % 2 == 0 : sym = NOSYM
      else          : sym = SYM_Y
      PlaceTop ( self.Pigi[i], sym )
        
    # Ligne des PG
    for n in range ( 1, ilog2(self._nbit) + 1, 2 ) :
      twostage += 1
      pi        = self._nbit - 1
      
      for i in range ( self._nbit - 1, 0, -1 ) :
        if i >= iexp2(n) + iexp2(n-1) and i & ( 1 << (n-1) ) :
        
          if pi % 2 == 0 : sym = NOSYM
          else           : sym = SYM_Y
          
          Place ( self.PgI1[n][i], sym, XY ( 125 + 55 * twostage, pi * 50 ) )
          Place ( self.PgI2[n][i], sym, XY ( 150 + 55 * twostage, pi * 50 ) )
            
          pi -= 1
        
        if i >= iexp2(n+1) + iexp2(n) and i & ( 1 << n ) :
        
          if pi % 2 == 0 : sym = NOSYM
          else           : sym = SYM_Y
          Place ( self.PgI1[n+1][i], sym, XY ( 125 + 55 * twostage, pi * 50 ) )
          Place ( self.PgI2[n+1][i], sym, XY ( 150 + 55 * twostage, pi * 50 ) )
            
          pi -= 1
    
    # nbit n'est pas une puissance entiere de 2
    if self._nbit % ( iexp2 ( ilog2 ( self._nbit ) - 1 ) ) : twostage += 1
      
    # Ligne retenue
    for n in range ( 2, self._nbit + 1 ) :
      if ( n - 1 ) % 2 == 0 : sym = NOSYM
      else                  : sym = SYM_Y
      Place ( self.R[n], sym, XY ( 125 + 55 * twostage, ( n - 1 ) * 50 ) )
    
        
    # Calcul des sommes
    if self._nbit > 1 : Place ( self.S[1], NOSYM, XY ( 155 + 55 * twostage, 0 ) )
    
    for i in range ( 2, self._nbit ) :
      if ( i - 1 ) % 2 == 0 : sym = NOSYM
      else                  : sym = SYM_Y
      PlaceTop ( self.S[i], sym )
    
  
    # Calcul somme et retenue du LSB
    Place ( self.S[0], NOSYM, XY ( 45, 0 ) )
  
  
  ########## VHDL ##########
  ##########################
  def Vbe ( self ) :

    name = self._name

    LV_flags = self._param['flags']
  
    fileName = name + ".vbe"
    
    file = open ( fileName, "w+" )
  
    sBusWide0 = VHDL_BUS_WIDE ( self._nbit - 1, 0, self._nbit, LV_flags )
    sBusWide1 = VHDL_BUS_WIDE ( self._nbit    , 1, self._nbit, LV_flags )
    sBusWide2 = VHDL_BUS_WIDE ( self._nbit    , 0, self._nbit, LV_flags )
  
    ## Entity description ##
    file.write ( "\nENTITY %s IS\n  PORT (\n" % name )
  
    file.write ( "%14s : in    BIT;\n"           % "add_sub" )
    file.write ( "%14s : out   BIT;\n"           % "c31" )
    file.write ( "%14s : out   BIT;\n"           % "c30" )
    file.write ( "%14s : in    BIT_VECTOR %s;\n" % ( "i0", sBusWide0 ) )
    file.write ( "%14s : in    BIT_VECTOR %s;\n" % ( "i1", sBusWide0 ) )
    file.write ( "%14s : out   BIT_VECTOR %s;\n" % (  "q", sBusWide0 ) )
  
    ## Power supplies terminals ##  
    file.write ( "%14s : in    BIT;\n" % "vdd" )
    file.write ( "%14s : in    BIT\n"  % "vss" )
    
    ## End of entity description ##
    file.write ( "  );\nEND %s;\n\n\n" %  name )
  
    ## Architecture description ##
    file.write ( "ARCHITECTURE VBE OF %s IS\n\n" % name )
  
    ## Signals ##  
    file.write ( "  SIGNAL %20s : BIT_VECTOR %s;\n" % ( "carry", sBusWide2 ) )
    file.write ( "  SIGNAL %20s : BIT_VECTOR %s;\n" % ( "xor_b", sBusWide0 ) )
  
    ## Behavior ##  
    file.write ( "\nBEGIN\n\n" )
  
    for i in range ( self._nbit - 1, -1, -1 ) :
      file.write ( "  xor_b(%ld) <= i1(%ld) xor add_sub;\n" % ( i, i ) )
      
    file.write ( "\n" )
  
    file.write ( "  carry(0) <= add_sub;\n\n" )
  
    file.write ( "  q <=     i0\n" )
    file.write ( "       xor xor_b\n" )
    file.write ( "       xor carry%s;\n\n"   % sBusWide0 )
  
    file.write ( "  c31 <=  carry(%ld);\n"   %   self._nbit       )
    file.write ( "  c30 <=  carry(%ld);\n\n" % ( self._nbit - 1 ) )
  
    file.write ( "  carry%s <=      (   i0 and xor_b)\n"        % sBusWide1 )
    file.write ( "               or (   i0 and carry%s)\n"      % sBusWide0 )
    file.write ( "               or (xor_b and carry%s);\n\n\n" % sBusWide0 )
  
    ## Assert ##
    file.write ( "  ASSERT (vdd = '1')\n" )
    file.write ( "    REPORT \"Power supply is missing on vdd of Model %s.\"\n" % name )
    file.write ( "    SEVERITY WARNING;\n\n" )
  
    file.write ( "  ASSERT (vss = '0')\n" )
    file.write ( "    REPORT \"Power supply is missing on vss of Model %s.\"\n" % name )
    file.write ( "    SEVERITY WARNING;\n\n" )
  
    ## End of Architectural description ##
    file.write ( "END VBE;\n" )
  
    file.close ()
