#!/usr/bin/env python
#
# -*- mode:Python -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC/LIP6 2008-2017, All Rights Reserved
#
# +-----------------------------------------------------------------+ 
# |                   C O R I O L I S                               |
# |  S t r a t u s   -  Netlists/Layouts Description                |
# |                                                                 |
# |  Author      :               Roselyne CHOTIN-AVOT               |
# |  E-mail      :       Roselyne.Chotin-Avot@lip6.fr               |
# | =============================================================== |
# |  Py Module   :       "./st_export.py"                           |
# +-----------------------------------------------------------------+

import os

from st_model import Model
from st_net import net

sep = "   "

# the list of components is updated at each new model to avoid to re-create them
COMPONENTS ={}

def write(model,format,extraLibs = []):
    if format == 'vhd':
        # create component for virtual library
        BV2VHDComponents()
        # remove all previous generation of files
        os.system("rm -f *.vhd *.vst")
        # create the VHDL model of the cell
        obj = VHDModel(model,extraLibs)
    else:
        raise "Not yet implemented format %s" %(format)
    # write the file
    obj.write()

# create component for virtual library
def BV2VHDComponents():
    from st_parser import BV
    from st_getrealmodel import GetRealModel

    for model in BV:
        (realM,inout) = GetRealModel(model)
        component = sep + "component %s\n" %realM + sep + "port (\n"
        for pin in inout:
            # stratus makes the asumption that pin names depend of the direction
            if pin in ['q','nq','sout','cout']: direct = "OUT"
            else: direct = "IN"
            component += sep + "%s: %s std_logic;\n" %(pin,direct)
        COMPONENTS[realM] = component[0:-2] + "\n" + sep + ");\n"

# Associated VHDL of stratus Model
# Create associated VHDL for :
#    - libraries
#    - ports
#    - instances
#    - and internal signals
class VHDModel():   
    def __init__(self, cell, extraLibs = []):
        self._cell = cell
        self._extraLibs = extraLibs
        self._str = ""
        self.model2vhd()
        self.write()

    def model2vhd(self):
        self._str += self.librairies2vhd()
        self._str += "entity " + self._cell._name + " is\n"
        self._str += self.ports2vhd()
        self._str += "end " + self._cell._name + ";\n"
        self._str += "\narchitecture structural of %s is\n" %self._cell._name
        self.insts2vhd()
        self._str += self._components
        self._str += self.sig2vhd()
        self._str += "begin\n"
        self._str += self._insts
        self._str += "end structural;\n"
        COMPONENTS[self._cell._name] = sep + "component %s\n" %self._cell._name + self._ports + sep + "end component;\n"
        
    def librairies2vhd(self):
        self._libs = "library ieee;\n"
        self._libs += "use ieee.std_logic_1164.all;\n\n"
        # the model used standard cells
        if 'realModel' in self._cell._param :
            self._libs += "library sxlib;\n"
            self._libs += "use sxlib.all;\n\n"
        for lib in self._extraLibs:
            self._libs = self._libs + lib + ";\n" 
        return self._libs

    def ports2vhd(self):
        self._ports = sep + "port(\n"
        for port in self._cell._st_ports + self._cell._st_cks:
            self._ports += sep + sep + VHDNet(port)._str
        self._ports = self._ports[0:-2]
        self._ports += "\n" + sep + ");\n"
        return self._ports

    def insts2vhd(self):
        self._insts = ""
        self._components = ""
        # list of the components of this model
        insts_components = []
        for inst in self._cell._st_insts:
            vhd_inst = VHDInst(inst)
            self._insts += vhd_inst._str
            # if it is not already present we add it
            if inst._model not in insts_components:
                insts_components.append(inst._model)
                self._components += COMPONENTS[inst._model]
        return self._insts

    def sig2vhd(self):
        self._sigs = ""
        for sig in self._cell._st_sigs:
            self._sigs += sep + "signal " + VHDNet(sig)._str
        return self._sigs
    
    def write(self):
        format = 'vhd'
        file = open(self._cell._name + "." + format, "w+")
        file.write( "--\n" )
        file.write( "-- Generated by Stratus export format %s\n" %format )
        file.write( "--\n" )
        file.write(self._str)
        file.close()
        
# Associated VHDL of stratus Net               
class VHDNet():
    def __init__(self, net):
        direct = ""
        # only external signals have a direction
        if net._ext:
            direct = net._direct
        self._str = "%s : %s std_logic" %(net._name,direct)
        if net._arity != 1:
            self._str += "_vector(%d downto 0)" %net._arity
        self._str += ";\n"

# Associated VHDL of stratus Inst
class VHDInst():
    def __init__(self, inst):
        # if the model is not yet in the components list we have to create it
        if inst._model not in COMPONENTS:
            model = VHDModel(inst._st_masterCell)
        self._str = sep + inst._name + " : " + inst._model + "\n"
        self._str += sep + sep + "port map (\n"
        for (k,v) in inst._map.iteritems():
            # the alim are not present in VHDL
            if not v._h_type or v._h_type not in ["POWER", "GROUND"]:
                # change the stratus' slice [] in VHDL's one ()
                name = v._name.replace('[','(').replace(']',')')
                self._str += sep + sep + sep +"%s => %s,\n" %(k,name)
        self._str = self._str[0:-2]
        self._str += "\n" + sep + sep + ");\n"

class VLog:
    def __init__(self, cell):
        raise "Not yet implemented"
        
## class VLogModel(ExportModel):
##     def __init__(self):
##         Export.__init__(self)

##     def createEntity(self):
##         ports = createPorts()
##         res = "module " + self._cell._name + " (\n"
##         res += ports[0]
##         res += ");\n"
##         res += ports[1]
##         return res    

class Json:
    def __init__(self, cell):
        raise "Not yet implemented"
