#!/usr/bin/python

FSM_STYLE="OneBlock"

# VHDL EDITOR PACKAGE
import sys, os, logging, datetime, math, unicodedata, re
import collections

from SysGen.Assignment import AssignmentStatement
#sys.path.append(os.path.abspath("./DesignTree"))
#import DesignTree

#from myhdl import *
Generator="YANGO"
ExtensionDict = {"VHDL": ".vhd", "Verilog":".v"}

#======================================================================
def Header(Module, Title, Purpose, Desc, Issues="", Speed="", Area="", Tool="Xilinx ISE (13.1)", Rev=""):
	"""
	Return string commented header.
	"""
	Head = """
----------------------------------------------------------------------------------------------------
-- Actual File Name      = {MODULE}.vhd
-- Title & purpose       = {TITLE} - {PURPOSE}
-- Author                = Automaticaly generated by {GENERATOR} - made by Matthieu PAYET (ADACSYS) - matthieu.payet@adacsys.com
-- Creation Date         = {TIME}
-- Version               = 0.1
-- Simple Description    = {DESCRIPTION}
-- Specific issues       = {ISSUES}
-- Speed                 = {SPEED}
-- Area estimates        = {AREA}
-- Tools (version)       = {TOOL}
-- HDL standard followed = VHDL 2001 standard
-- Revisions & ECOs      = {REV}
----------------------------------------------------------------------------------------------------
	"""
	return Head.format(
			GENERATOR=Generator,
			MODULE=Module, 
			TITLE=Title, 
			PURPOSE=Purpose, 
			DESCRIPTION=Desc, 
			ISSUES=Issues, 
			SPEED=Speed, 
			AREA=Area, 
			TOOL=Tool, 
			REV=Rev,
			TIME=datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))


#======================================================================
def Libraries(LibList):
	Headers=""
	for Lib in list(set(LibList)):
		Headers+="\nlibrary {0};".format(Lib)
	return Headers

#======================================================================
def Packages(PackageList, All=True):
	Code=""
	for PackageName in PackageList:
		Code+=Package(PackageName, All)
	return Code
	
#======================================================================
def Package(PackageName, All=True):
	if All: return "\nuse {0}.all;".format(PackageName)
	else: return "\nuse {0};".format(PackageName) 

#======================================================================
def AbsoluteAssignment(AssignmentList):
	"""
	Return code for data flow absolute assignments.
	"""
	Code =  "\n"+"--"*30
	Code+= "\n-- Direct connections"
	Code += "\n"+"--"*30
	for A in AssignmentList:
		Code+= If(A, Comments=A.Desc()) # TODO : Use "when" instead
	Code+= "\n"+"--"*30
	return Code
	
#======================================================================
def Process(Name, SensitivList, Declarations, Content, Comments=""):
	"""
	Return code for process declaration and insert specified content/declaration List.
	"""
	Text = "\n\n"+"--"*30
	Text+= "\n"+Comment("Process "+Name+" : "+Comments)
	Text+= "\n{0}: process(".format(Name)+", ".join([str(x) for x in SensitivList])+")\n"
	Text+= Indent( Declarations )
	Text+= "\nbegin\n"
	Text+= Indent( Content )
	Text+= "\n\nend process;\n"
	Text+= "--"*30
	
	return Text
	
#======================================================================
def SyncProcess(Name, Clock=None, Reset=None, Declarations="", SyncAssignments=[], InitAssignments=[], Comments="Synchronous process"):
	"""
	Return code for synchronous process implementation.
	"""
	SC=SyncCondition(ClockName=str(Clock), EveryEdge=False, Rising=True)
	SyncAssignments=AssignmentStatement(Assignee=SyncAssignments, Assignor=None, Cond=SC, Desc="")
	
	ASyncAssignments=AssignmentStatement(Assignee=SyncAssignments, Assignor=None, Cond=Equals(ValueA=Reset, ValueB=0, Size=1), Desc="")
	ASyncAssignments.Add(Assignee=InitAssignments, Assignor=None, Cond=None, Desc="")
	
	Content=If(ASyncAssignments, Comments="")
	return Process(Name, SensitivList=[Clock, Reset], Declarations=Declarations, Content=Content, Comments=Comments)
	
#======================================================================
def SyncCondition(ClockName, EveryEdge=False, Rising=True):
	"""
	Return code for clock synchronous condition.
	"""
	if EveryEdge:
		return "{0}'event".format(ClockName)
	else:
		if Rising:
			return "rising_edge({0})".format(ClockName)
		else:
			return "falling_edge({0})".format(ClockName)

#======================================================================
def Entity(Name, Generics=[], Ports=[], Comments="Empty entity"):
	Text="\n"+"--"*40
	Text+="\n-- ENTITY: {0} - {1}\n".format(Name, Comments)
	Text+="--"*40
	PortDeclaration=""
	GenericDeclaration=""
	if len(Generics):
		GenericDeclaration="\ngeneric("
		while Generics.count([]): Generics.remove([])
		MGW = max([len(x.GetName()) for x in Generics])
		MGTW = max([len(x.GetType()) for x in Generics])
		for G in Generics:
			GenericDeclaration+=Indent(Generic(("{0:"+str(MGW)+"}").format(G.Name), ("{0:"+str(MGTW)+"}").format(G.GetType()), G.GetValue())+";")
		GenericDeclaration=GenericDeclaration[:-1]+");"
	if len(Ports):
		PortDeclaration="\nport("
		# Get max port names width
		MPW = max([len(x.GetName()) for x in Ports])
		for P in Ports:
			PortDeclaration+=Indent(Port(("{0:"+str(MPW)+"}").format(P.GetName()), "{0:3}".format(P.Direction), P.GetType()))+";"
		PortDeclaration=PortDeclaration[:-1]+"\n);"
	return Text+"\nentity {0} is {1}{2}\nend entity {0};\n".format(Name, Indent(GenericDeclaration), Indent(PortDeclaration))
	
#======================================================================
def Port(PortName, IO, PortType):
	return "\n{0} : {1} {2}".format(PortName, IO, PortType)
	
#======================================================================
def Generic(GenericName, GenericType, GenericValue):
	if GenericType.find("integer")!=-1: Type="integer"
	else: Type=GenericType
	return "\n{0} : {1} := {2}".format(GenericName, Type, GenericValue)
		
#======================================================================
def Architecture(Name, Entity, Declarations="", Content="", Comments="Version 0"):
	"""
	Return code for the architecture of a module in VHDL.
	An instance is made up of 5 data (in a list) : InstanceName, Module, SignalDict, GenericDict, comment.
	A signal is described by its SignalName, SignalType and InitialValue (in a list). 
	"""
	Text="\n"+"--"*40
	Text+="\n-- ARCHITECTURE: {0} - {1}\n".format(Name, Comments)
	Text+="--"*40
	return Text+"\narchitecture {0} of {1} is\n{2}\n\nbegin\n{3}\n\nend architecture {0};\n\n".format(Name, Entity, Indent(Declarations), Indent(Content))
	
#======================================================================
def Constant(ConstName, ConstType, Value, Size=1):
	return "\nconstant {0} : {1} := {2};".format(ConstName, NormalizeType(ConstType), Value)
	

#======================================================================
#def Type(TypeName, ValueList, InitialValue=None):
#	"""
#	Return code for type declaration.
#	"""
#	if InitialValue:
#		return "type {0} is ("+",".join(ValueList)+");"
#	else:
#		return "type {0} is ("+",".join(ValueList)+") := {0};".format(InitialValue)
#
#======================================================================
def Instantiate(InstanceName, Module, Architecture=None, SignalDict={}, GenericDict={}, Comment=""):
	"""
	Generate code for instanciation (VHDL)
	"""
#	logging.debug("Instanciate sub-module {0} as instance {1}.".format(Module, InstanceName))
	Text=""
	if Comment!="": Text+="\n-- "+Comment
	if(Architecture!=None and Architecture!=""):
		Text +="\n{0}: entity work.{1}({2})".format(InstanceName, Module, Architecture)
	else: 
		Text +="\n{0}: entity work.{1}".format(InstanceName, Module)

	if len(GenericDict)>0:
		Text+="\n\tgeneric map(\n\t\t"
		Links=[]
		MaxWidth = max([len(x) for x in GenericDict])
		for GenericValue, Actual in list(GenericDict.items()):
			if isinstance(Actual, Signal):
				Links.append(("{0:"+str(MaxWidth)+"}").format(GenericValue)+' => '+str(Actual.GetName()))
			else: 
				Links.append(("{0:"+str(MaxWidth)+"}").format(GenericValue)+' => '+str(Actual))
		Text+=",\n\t\t".join(Links)+"\n\t\t)"
	
	if len(SignalDict)>0:
		Text+="\n\tport map(\n\t\t"
		Links=[]
		MaxWidth = max([len(x) for x in SignalDict])
		for SignalName, Actual in list(SignalDict.items()):
			if isinstance(Actual, Signal):
				Links.append(("{0:"+str(MaxWidth)+"}").format(SignalName)+' => '+str(Actual.GetName()))
			else: 
				Links.append(("{0:"+str(MaxWidth)+"}").format(SignalName)+' => '+str(Actual))
		Text+=",\n\t\t".join(Links)+"\n\t\t);"
		
	return Text

#======================================================================
def Case(SignalName, Assignment, Comments=""):
	"""
	Return code for process declaration and insert specified content/declaration List.
		Assignment:  AssignmentStatement instance
	"""
	Text="\ncase {0} is ".format(SignalName)+Comment(Comments)
	NullAssignments=[]
	for Condition, Statements in Assignment:
		if Condition is None: 
			NullAssignments+=Statements
			continue
		
		Text+= Indent( "\nwhen {0} =>".format(Condition) )
		for S in Statements:
			if isinstance(S, AssignmentStatement):
				Text+=Indent(If(S, Comments=S.Desc()), 2)
			else:
				if not isinstance(S, dict):
					logging.error("[HDL:Case] Statement must be a AssignmentStatement instance or a Statement dictionary.")
					continue
				A=S["Assignee"]
				if isinstance(A, AssignmentStatement):
					Text+=Indent(If(A, Comments=A.Desc()), 2)
				elif not isinstance(A, Signal):
					logging.error("[HDL:Case] Assignee must be a Signal or AssignmentStatement instance.")
				else:
					Text+=Indent(A.Connect(S["Assignor"]))
#	if not AssignmentDict.keys().count("others"):
	if len(NullAssignments)==0:
		Text+= Indent( "\nwhen others => null;" )
	else:
		Text+= Indent( "\nwhen others =>" )
		for S in NullAssignments:
			if isinstance(S, AssignmentStatement):
				Text+=Indent(If(S, Comments=S.Desc()), 2)
			else:
				if not isinstance(S, dict):
					logging.error("[HDL:Case] Statement must be a AssignmentStatement instance or a Statement dictionary.")
					continue
				A=S["Assignee"]
				if isinstance(A, AssignmentStatement):
					Text+=Indent(If(A, Comments=A.Desc()), 2)
				elif not isinstance(A, Signal):
					logging.error("[HDL:Case] Assignee must be a Signal or AssignmentStatement instance.")
				else:
					Text+=Indent(A.Connect(S["Assignor"]))
		
	Text+= "\nend case;\n"
	
	return Text

#======================================================================
def If(Assignment, Comments=""):
	"""
	Return code for if/elsif/else declaration according to Condition/Action pairs in Allocation List.
	Else item is represented by a condition='None'.
	"""
	Text=""
	FirstItem=True
	if not isinstance(Assignment, AssignmentStatement):
		raise TypeError("[HDL:If] Statement must be a dictionary, not '{0}'.".format(type(Assignment)))
	for Condition, Statements in Assignment:
		if not Condition or str(Condition)=="":
			if FirstItem:
				# No need for 'if' statement
				for SDict in Statements:
					if isinstance(SDict, dict):
						A=SDict["Assignee"]
						if isinstance(A, Signal):
							Text+=A.Connect(SDict["Assignor"])
						elif isinstance(A, AssignmentStatement):
							Text+=If(A, Comments=A.Desc())
						elif isinstance(A, dict):
							Text+=Case(A["Name"], A["Assignments"], A["Comments"])
						else:
							logging.error("[HDL:If] Assignee must be a Signal or AssignmentStatement instance, not '{0}'.".format(type(A)))
					else:
						logging.error("[HDL:If] Statement must be a dictionary, not '{0}'.".format(type(SDict)))
			else:
				# LAST CONDITION--------------------------------------
				AList=[]
				for SDict in Statements:
					if isinstance(SDict, dict):
						A=SDict["Assignee"]
						if isinstance(A, Signal):
							AList.append( "{0}".format(A.Connect(SDict["Assignor"]) ))
						elif isinstance(A, AssignmentStatement):
							AList.append( "{0}".format(If(A, Comments=A.Desc()) ))
						else:
							logging.error("[HDL:If] Assignee must be a Signal or AssignmentStatement instance, not '{0}'.".format(type(SDict)))
					else:
						logging.error("[HDL:If] Statement must be a dictionary, not '{0}'.".format(type(SDict)))
				Text+="\nelse {0}".format(Indent( "".join(AList) ))
		else:
			# FIRST CONDITION--------------------------------------
			if FirstItem:
				AList=[]
				for S in Statements:
					if isinstance(S, dict):
						A=S["Assignee"]
						if isinstance(A, Signal):
							A=AssignmentStatement(Assignee=A, Assignor=S["Assignor"], Cond=None, Desc="")
							AList.append( If(A, Comments="") )
						elif isinstance(A, AssignmentStatement):
							AList.append( If(A, Comments="") )
						else:
							logging.error("[HDL:If] Assignee must be a Signal or AssignmentStatement instance, not '{0}'.".format(type(A)))
					else:
						logging.error("[HDL:If] Statement must be a dictionary, not '{0}'.".format(type(S)))
				Text+="\nif {0} then {1}".format(Condition, Indent("".join(AList)))
				FirstItem=False
			# OTHER CONDITION--------------------------------------
			else:
				AList=[]
				for S in Statements:
					if isinstance(S, dict):
						A=S["Assignee"]
						if isinstance(A, Signal):
							A=AssignmentStatement(Assignee=A, Assignor=S["Assignor"], Cond=None, Desc="")
							AList.append( If(A, Comments="") )
						elif isinstance(A, AssignmentStatement):
							AList.append( If(A, Comments="") )
						else:
							logging.error("[HDL:If] Assignee must be a Signal or AssignmentStatement instance, not '{0}'.".format(type(A)))
					else:
						logging.error("[HDL:If] Statement must be a dictionary, not '{0}'.".format(type(S)))
				Text+="\nelsif {0} then {1}".format(Condition, Indent("".join(AList)))
				
	if not FirstItem:
		return Text+"\nend if;"
	else: 
		return Text
	
##======================================================================
#def SyncCondition(SignalName):
#	return "rising_edge({0})".format(SignalName)

#======================================================================
def For(Name, Var, Start, Stop, Content, Comments=""):
	"""
	Return code for 'for' declaration of a content.
	"""
	Text="\n{0}: for {1} in {2} to {3} generate {4}\nend generate {0};".format(Name, Var, Start, Stop, Indent(Content))
	return "\n--"+Comments+Text
		
#======================================================================
def LogicValue(Integer, BitLength):
	if Integer is None:
		Integer=0
	if int(BitLength)<2:
		if int(Integer)>1:
			logging.error("[LogicValue] Bit value '{0}' for bit length '{1}' is higher than 1: set 0 instead.".format(Integer, int(BitLength)))
			return "'0'"
		else:
			return "'{0:b}'".format(int(Integer))
	else:
		if isinstance(Integer, str): I=int(Integer, 2)
		else: I=int(Integer)
		return str('"{0:0'+str(int(BitLength))+'b}"').format(I)
		

#======================================================================
def Equals(ValueA, ValueB=None, Size=1):
	if ValueB:
		if isinstance(ValueB, int): 
			return "({0})".format(Associate(ValueA, LogicValue(ValueB, Size), "="))
		else:
			return "({0})".format(Associate(ValueA, ValueB, "="))
	else:
		if Size>1: return "({0})".format(Associate(ValueA, "(others=>'0')", "="))
		else: return "({0})".format(Associate(ValueA, "'0'", "="))
		
#======================================================================
def NotEquals(ValueA, ValueB=None, Size=1):
	if ValueB:
		if isinstance(ValueB, int): 
			return "({0})".format(Associate(ValueA, LogicValue(ValueB, Size), "/="))
		else:
			return "({0})".format(Associate(ValueA, ValueB, "/="))
	else:
		if Size>1: return "({0})".format(Associate(ValueA, "(others=>'0')", "/="))
		else: return "({0})".format(Associate(ValueA, "'0'", "/="))

#======================================================================
def Associate(ValueA, ValueB, Symbol='='):
	return "{0} {1} {2}".format(ValueA, Symbol, ValueB)

#======================================================================
def Assign(S0, S1):
	if isinstance(S1, Signal):
		return Associate(S0.GetName(), S1.GetName(), Symbol='<=')+';'
	else:
		return Associate(S0.GetName(), str(S1), Symbol='<=')+';'

#======================================================================
def Indent(Text, TabNB=1):
	"""
	Add specified number of tabulation to each line of the text and return it.
	"""
	if Text: 
		Indented = str(Text).replace("\n", "\n"+"\t"*TabNB)
		if Indented.startswith('\n'):
			return Indented
		else:
			return "\n"+"\t"*TabNB+Indented
	else: return ""

#======================================================================
def Comment(Text):
	if Text: 
		CommmentedText = str(Text).replace("\n", "\n"+"-- ")
		if not CommmentedText.startswith('--'): CommmentedText= "-- "+CommmentedText
		return CommmentedText
	else: return ""
	

#======================================================================
def NormalizeType(SignalType, Size, IsArray=False, Direction=None, UnConstrained=False):
	if SignalType == "logic": 
		try: Max=int(Size)-1
		except: Max=str(Size)+"-1"
		try: 
			S = int(Size)
			if S==1: return "std_logic"
			elif S>1:
				if UnConstrained is True:
					return "std_logic_vector"
				else: 
					return "std_logic_vector({0} downto {1})".format(str(Max), 0)
			else: raise NameError("Unable to recognize size format '{0}': aborted.".format(S))
		except: 
			if UnConstrained is True:
				return "std_logic_vector"
			else: 
				return "std_logic_vector({0} downto {1})".format(Max, 0)
			
	elif  SignalType == "numeric": 
		#if Size==None: return "natural"
		#else: return "natural range 0 to {0}".format(int(math.pow(2, float(Size))))
		return "natural"
	else: 
		try: 
			Max=int(Size)-1
			if Size==1:
				Vector=False
			else:
				Vector=True
				#print "#\n#SignalType:", SignalType,"(size", Size,") IsArray:", IsArray,"\n#"
		except: 
			Max=str(Size)+"-1"
			Vector=True
		
		if Vector:
			if UnConstrained is True or (Size is None):
				return SignalType
			else: 
				return SignalType+"({0} downto {1})".format(str(Max), 0)
		else: 
			if IsArray and not (Direction is None): 
				if UnConstrained is True:
					return SignalType
				else: 
					return SignalType+"(0 downto 0)" 
			else:  return SignalType
				
		#raise NameError("Unable to recognize size format '{0}': aborted.".format(Size))

#======================================================================
def NewName(BaseName, NameList):
	"""
	Return a Name that is unique to the list, based on the pattern Base-Name + number
	"""
	NameList=list(NameList)
	NB = 0
	while NameList.count("{0}_{1}".format(BaseName, NB)): NB+=1
	return 	"{0}_{1}".format(BaseName, NB)
	
#======================================================================
def PkgDeclaration(Name, Declaration=''):
	"""
	Return code for Package declaration.
	"""
	return "\npackage {0} is\n{1}\n\nend {0};".format(Name, Indent(Declaration))

#======================================================================
def PkgBody(Name, Body=""):
	"""
	Return code for Package body.
	"""
	return "\npackage body {0} is\n{1}\n\nend {0};".format(Name, Indent(Body))

#======================================================================
def Type(TName, TType):
	"""
	Return code for type declaration.
	"""
	return "\ntype {0} is {1};".format(TName, TType)

#======================================================================
def SubType(TName, TType):
	"""
	Return code for type declaration.
	"""
	return "\nsubtype {0} is {1};".format(TName, TType)
	
#======================================================================
def ArrayType(Name, Size, SubType, ArraySize=None, CustomElmts=[]):
	"""
	Return code for array type declaration.
	"""
	if len(CustomElmts)>0:
		return "\ntype {0} is ({1});".format(Name, ", ".join(map(str, CustomElmts)))
	elif not (ArraySize is None): 
		return "\ntype {0} is array(natural range 0 to {1}-1) of {2};".format(Name, ArraySize, NormalizeType(SubType, Size))
	elif SubType=="numeric":
		if Size!=None: 
			return "\ntype {0} is array(natural range 0 to {1}-1) of {2};".format(Name, Size, NormalizeType(SubType, Size))
		else: 
			return "\ntype {0} is array(natural range <>) of {1};".format(Name, NormalizeType(SubType, Size))
	else: 
		return "\ntype {0} is array(natural range <>) of {1};".format(Name, NormalizeType(SubType, Size))
	
#======================================================================
def Access(NewType, Accessed):
	"""
	Return code for VHDL Access declaration of type pointer.
	"""
	return "\ntype {0} is access {1};".format(NewType, Accessed)
	
#======================================================================
def FSM_3Blocks(StateGraph, Name, Clock, Reset):
	"""
	Return code for VHDL FSM.
	"""
#	logging.debug("Build VHDL FSM...")
	Declaration=""
	Content=""
	
	# FSM State register-------------------------------------------
	Nodes=StateGraph.Nodes()
#	NBNodes=len(Nodes)
	TypeName="STATE_{0}".format(Name.upper())
	FuturState   = Signal("FuturState_{0}_i".format(Name), Direction="IN", Size=1, Type=TypeName, InitVal="STATE_INIT", IsArray=False)
	CurrentState = Signal("CurrentState_{0}_i".format(Name), Direction="IN", Size=1, Type=TypeName, InitVal="STATE_INIT", IsArray=False)
	Declaration+=ArrayType(TypeName, 0, SubType=None, ArraySize=None , CustomElmts=Nodes)
	Declaration+=FuturState.Declare(Constant=False, UnConstrained=True)
	Declaration+=CurrentState.Declare(Constant=False, UnConstrained=True)
	
	SA=AssignmentStatement(Assignee=CurrentState, Assignor=FuturState, Cond=None, Desc="SyncAssignments")
	IA=AssignmentStatement(Assignee=CurrentState, Assignor=None, Cond=None, Desc="InitAssignments")
	Content+=SyncProcess("FSMStateRegister_{0}".format(Name), Clock=Clock, Reset=Reset, Declarations="", SyncAssignments=SA, InitAssignments=[IA,]+StateGraph.GetResetAssignments(), Comments="FSM State Register")
	
	# FSM State assignment-----------------------------------------
	FSMAssignment=AssignmentStatement(Desc="FSM State assignment")
#	logging.debug("Futur states assignment.")
	SensitivityList=[]
	# Futur states assignment
	for Node in sorted(Nodes, key=lambda N: N.Position):
		StateAssignments=AssignmentStatement()
		FSMAssignment.Add(Assignee=StateAssignments, Assignor=None, Cond=Node.GetName(), Desc="")
		
		#------------------------
		# Fill the sensitivity list
		for EC in list(Node.GetEnteringCondition().values()):
			if not EC: continue
			for S in EC.GetSignals():
				if not S.Name in [x.Name for x in SensitivityList]:
					SensitivityList.append(S)
		#------------------------
		# Assign signals in state
		for A in Node.GetAssignments():
			StateAssignments.Add(Assignee=A, Assignor=None, Cond=None, Desc="")
			
		#------------------------
		ElseCond=None
		for Successor in StateGraph.Graph.successors(Node):
			# Assign future state with successors
			EC=Successor.GetEnteringCondition()[Node]
			if EC is None:
				ElseCond=Successor
			else:
				StateAssignments.Add(Assignee=FuturState, Assignor=str(Successor), Cond=EC, Desc="")
		if ElseCond: 
			ECAssignment=StateAssignments.Add(Assignee=FuturState, Assignor=str(ElseCond), Cond=None, Desc="")
			
	
#	logging.debug("Generate 'Case' content.")
	CaseContent=Case(FuturState.GetName(), FSMAssignment, Comments="Assignments for FSM FuturState")
		
#	logging.debug("Generate 'Process' content.")
	Content+=Process("FSMStateAssignment_{0}".format(Name), [CurrentState,]+SensitivityList, Declarations="", Content=CaseContent, Comments="FSM State assignments")
	
#	logging.debug("FSM generated.")	
	return Declaration, Content
	
#======================================================================
def FSM_OneBlock(StateGraph, Name, Clock, Reset):
	"""
	Return code for VHDL FSM.
	"""
#	logging.debug("Build VHDL FSM...")
	Declaration=""
	Content=""
	
	# FSM State register-------------------------------------------
	Nodes=StateGraph.Nodes()
#	NBNodes=len(Nodes)
	TypeName="STATE_{0}".format(Name.upper())
	CurrentState = Signal("CurrentState_{0}_i".format(Name), Direction="IN", Size=1, Type=TypeName, InitVal="STATE_INIT", IsArray=False)
	Declaration+=ArrayType(TypeName, 0, SubType=None, ArraySize=None , CustomElmts=Nodes)
	Declaration+=CurrentState.Declare(Constant=False, UnConstrained=True)
	for Sig in StateGraph.GetUsedSignals():
		Declaration+=Sig.Declare(Constant=False, UnConstrained=False)
	
	# FSM State assignment-----------------------------------------
	FSMAssignment=AssignmentStatement(Desc="FSM State assignment")
	# Futur states assignment
	for Node in sorted(Nodes, key=lambda N: N.Position):
		StateAssignments=AssignmentStatement()
		
		#------------------------
		# TODO: Remove Double assignments
		# Assign signals in state
		for A in Node.GetAssignments():
			StateAssignments.Add(Assignee=A, Assignor=None, Cond=None, Desc="")
			
		#------------------------
		ElseCond=None
		for Successor in StateGraph.Graph.successors(Node):
			# Assign future state with successors
			EC=Successor.GetEnteringCondition()[Node]
			if EC is None:
				ElseCond=Successor
			else:
				StateAssignments.Add(Assignee=CurrentState, Assignor=str(Successor), Cond=EC, Desc="")
				TransAssignments=Node.GetTransitionAssignments()
				if len(TransAssignments):
					for A in TransAssignments:
						StateAssignments.Add(Assignee=A, Assignor=None, Cond=EC, Desc="")
						
		if ElseCond: 
			ECAssignment=StateAssignments.Add(Assignee=CurrentState, Assignor=str(ElseCond), Cond=None, Desc="")
			
#		print("\t*Assign {0} to {0}".format(StateAssignments))
		FSMAssignment.Add(Assignee=StateAssignments, Assignor=None, Cond=Node.GetName(), Desc="")
			
	
#	logging.debug("Generate 'Case' content.")
	CaseDict={"Name": CurrentState.GetName(), "Assignments":FSMAssignment, "Comments":"Assignments for FSM FuturState"}
	CaseAssignments=AssignmentStatement(Assignee=CaseDict, Cond=None)
	
#	logging.debug("Generate 'Process' content.")
	IA=AssignmentStatement(Assignee=CurrentState, Assignor=None, Cond=None, Desc="InitAssignments")
	Content+=SyncProcess("FSMStateAssignment_{0}".format(Name), Clock=Clock, Reset=Reset, Declarations="", SyncAssignments=CaseAssignments, InitAssignments=[IA,]+StateGraph.GetResetAssignments(), Comments="FSM State assignments")
		
#	logging.debug("FSM generated.")	
	return Declaration, Content
	
#======================================================================
def FSM_2Blocks(StateGraph, Name, Clock, Reset):
	"""
	Return code for VHDL FSM.
	"""
#	logging.debug("Build VHDL FSM...")
	Declarations=""
	Content=""
	
	# FSM State register-------------------------------------------
	Nodes=StateGraph.Nodes()
#	NBNodes=len(Nodes)
	TypeName="STATE_{0}".format(Name.upper())
	CurrentState = Signal("CurrentState_{0}_i".format(Name), Direction="IN", Size=1, Type=TypeName, InitVal="STATE_INIT", IsArray=False)
	Declarations+=ArrayType(TypeName, 0, SubType=None, ArraySize=None , CustomElmts=Nodes)
	Declarations+=CurrentState.Declare(Constant=False, UnConstrained=True)
	
	for Sig in StateGraph.GetUsedSignals():
		Declarations+=Sig.Declare(Constant=False, UnConstrained=False)
	
	# FSM State assignment-----------------------------------------
	FSMAssignment=AssignmentStatement(Desc="FSM State assignment")
	# Futur states assignment
	for Node in sorted(Nodes, key=lambda N: N.Position):
		StateAssignments=AssignmentStatement()
		
		if len(StateGraph.CounterSignals)!=0:
			for A in Node.GetAssignments(ReqList=StateGraph.CounterSignals):
				StateAssignments.Add(Assignee=A, Assignor=None, Cond=None, Desc="")
		#------------------------
		# TODO: Remove Double assignments
		#------------------------
		ElseCond=None
		for Successor in StateGraph.Graph.successors(Node):
			# Assign future state with successors
			EC=Successor.GetEnteringCondition()[Node]
			if EC is None:
				ElseCond=Successor
			else:
				StateAssignments.Add(Assignee=CurrentState, Assignor=str(Successor), Cond=EC, Desc="")
						
		if ElseCond: 
			ECAssignment=StateAssignments.Add(Assignee=CurrentState, Assignor=str(ElseCond), Cond=None, Desc="")
			
#		print("\t*Assign {0} to {0}".format(StateAssignments))
		FSMAssignment.Add(Assignee=StateAssignments, Assignor=None, Cond=Node.GetName(), Desc="")
			
	
#	logging.debug("Generate 'Case' content.")
	CaseDict={"Name": CurrentState.GetName(), "Assignments":FSMAssignment, "Comments":"Assignments for FSM FuturState"}
	CaseAssignments=AssignmentStatement(Assignee=CaseDict, Cond=None)
	
#	logging.debug("Generate 'Process' content.")
	IA=AssignmentStatement(Assignee=CurrentState, Assignor=None, Cond=None, Desc="InitAssignments")
	Content+=SyncProcess("FSMStateAssignment_{0}".format(Name), Clock=Clock, Reset=Reset, Declarations="", SyncAssignments=CaseAssignments, InitAssignments=[IA,], Comments="FSM State assignments")
	
	#-----------------------------------
	# SIGNAL ASSIGNMENT BLOC
	SensitivityList=[]
	FSMAssignment=AssignmentStatement(Desc="{0} FSM signal assignment".format(Name))
	for RA in StateGraph.GetResetAssignments():
		FSMAssignment.Add(Assignee=RA, Assignor=None, Cond=None, Desc="")
	for Node in sorted(Nodes, key=lambda N: N.Position):
		StateAssignments=AssignmentStatement()
		for A in Node.GetAssignments(SkipList=StateGraph.CounterSignals):
			StateAssignments.Add(Assignee=A, Assignor=None, Cond=None, Desc="")
			
		#------------------------
		# Fill the sensitivity list
		for EC in list(Node.GetEnteringCondition().values()):
			if not EC: continue
			TransAssignments=Node.GetTransitionAssignments()
			if len(TransAssignments):
				for A in TransAssignments:
					StateAssignments.Add(Assignee=A, Assignor=None, Cond=EC, Desc="")
			for S in EC.GetSignals():
				if not S.Name in [x.Name for x in SensitivityList]:
					if not (S.Name in StateGraph.CounterSignals): SensitivityList.append(S)
		FSMAssignment.Add(Assignee=StateAssignments, Assignor=None, Cond=Node.GetName(), Desc="")
	
	Content+=Process(
			Name="FSMSignalAssignments_{0}".format(Name), 
			SensitivList=[CurrentState, ]+SensitivityList, 
			Declarations="", 
			Content=Case(CurrentState.GetName(), FSMAssignment, Comments="Assignments for FSM FuturState"), 
			Comments="Signal assignments according to {0} FSM state.".format(Name)
			)
#	logging.debug("FSM generated.")	
	return Declarations, Content


#==================================================================
# Signal object
#==================================================================
class Signal:
	"""
	Object that contains basic parameters for a signal definition.
	"""
	#----------------------------------------------------------------------
	def __init__(self, Item, Direction="IN", Size=1, Type=None, InitVal=0, CurValue=0, IsArray=False, GenericSize=None, Vars={}):
#		if GenericSize is None: raise TypeError
		if isinstance(Item, Signal):
			self.Name      = Item.Name
			self.Direction = Item.Direction # Always in capital letters
			self.Size      = Item.Size # an integer or a string  
			self.GenericSize=Item.GenericSize
			self.Type      = Item.Type
			self.InitVal   = Item.InitVal # string or integer or list
			self.Index     = Item.Index
			self.IsArray   = Item.IsArray
			self.Value     = Item.Value
			self.TestCond  = Item.TestCond
		elif isinstance(Item, list) or isinstance(Item, tuple):
			if len(Item)==0: raise TypeError("HDLEditor.Signal cannot be built from an empty list.")
			for Elmt in Item:
				if not isinstance(Elmt, Signal): raise TypeError("HDLEditor.Signal cannot be built from list of non signal instances (received '{0}').".format(Item))
			TEMP=Item[0]
#			print("TEMP:", TEMP, "/", TEMP.Value)
			for Elmt in Item[1:]:
#				print("Elmt:", Elmt, "/", Elmt.Value)
				TEMP=TEMP.Concatenate(Elmt, Vars=Vars)
			self.Name      = TEMP.Name
			self.Direction = TEMP.Direction # Always in capital letters
			self.Size      = TEMP.Size # an integer or a string  
			self.GenericSize=TEMP.GenericSize
			self.Type      = TEMP.Type
			self.InitVal   = TEMP.InitVal # string or integer or list
			self.Index     = TEMP.Index
			self.IsArray   = TEMP.IsArray
			self.Value     = TEMP.Value
			self.TestCond  = TEMP.TestCond
		else:
			self.Name      = Item              # a string
			if Direction: self.Direction = Direction.upper() # "IN" or "OUT" # Always in capital letters
			else: self.Direction = None # Should be None
			self.Size      = Size         # an integer    
			self.GenericSize=self.Size if GenericSize is None else GenericSize
			self.Index     = None
			self.Type      = Type
			self.IsArray   = IsArray
			if IsArray and not isinstance(InitVal, list) and not (InitVal is None):
				logging.warning("[Signal '{2}'] Initial value ('{0}') of array signal '{1}' is not a list.".format(InitVal, self.Name, self)) 
#				raise TypeError
			self.InitVal   = InitVal            # string or integer
			
			self.Value = self.ConvertType(0, TypeOfValue="natural") if CurValue is None else self.ConvertType(CurValue, TypeOfValue=None) # string or integer
		
			if self.IsArray and self.Size==1:
				self.SetIndex(0)
			
			self.TestCond=OPSYMBOL_DICT['__eq__']
	#----------------------------------------------------------------------
	def GetName(self):
		if self.Index!=None or (self.IsArray and self.Size==1):
			if isinstance(self.Index, list):
				start, stop = self.Index
				return self.Name+"({0} downto {1})".format(str(stop), start) 
			return self.Name+"({0})".format(self.Index)
		else: 
			return self.Name.replace(".", "_")
	#---------------------------------------------------------------
	def AVAName(self):
		"""
		Return signal name respecting AVA format.
		"""
		if self.Index!=None or (self.IsArray and self.Size==1):
			if isinstance(self.Index, list):
				start, stop = self.Index
				return self.Name+"({0}:{1})".format(str(stop), start) 
			return self.Name+"({0})".format(self.Index)
		else: 
			if self.Size>1: return self.Name+"({0}:{1})".format(self.Size-1, 0) 
			else: return self.Name
	#----------------------------------------------------------------------
	def GetSize(self, Full=False, Vars={}):
		if Full:
			if isinstance(self.GetType(), str):
				return self.Size
			else:
				return self.Size*self.Type.GetSize()
		else:
			try: return int(eval(self.Size, Vars.copy()))
			except: return self.Size
	#----------------------------------------------------------------------
	def GetType(self, UnConstrained=False):
		Type=None
		if self.Type: 
			if isinstance(self.Type, Signal):
				if self.GenericSize is None: 
					logging.error("Signal array '{0}' has no size.".format(self.Name))
					Type="ARRAY{0}_{1}".format(1, self.Type.Type)
				else:
					Type="ARRAY{0}_{1}".format(self.GenericSize, self.Type.Type)
			else: 
				Type=NormalizeType(self.Type, self.GenericSize, IsArray=self.IsArray, Direction=self.Direction, UnConstrained=UnConstrained)
		else: 
			Type=NormalizeType("logic", self.GenericSize, IsArray=False, Direction=self.Direction, UnConstrained=UnConstrained)
		return Type
	#----------------------------------------------------------------------
	def SetValue(self, Val, TypeOfValue=None):
		"""
		Set Value attribute (eventually with type conversion).
		"""		
		self.Value=self.ConvertType(Val, TypeOfValue=TypeOfValue)
		return self.Value
	#----------------------------------------------------------------------
	def GetValue(self, Val=None, WriteBits=False, Vars={}):
		"""
		return HDL format for Value Val or self.InitVal.
		"""		
		# Get size of signal----------------------------------
		if isinstance(self.Index, list): 
			Size=eval(str(self.Index[1])+"+1-"+str(self.Index[0]), Vars)
		elif isinstance(self.Index, int): 
			Size=1
		else: 
			if self.Size is None: Size=32 # Temporary ! TODO: resolve None issue
			else: Size=eval(str(self.Size), Vars)
		if self.Type:	
			if self.Type.startswith("STATE"): # FSM State # TODO make it portable !
				if isinstance(Val, str): return Val
				else: 
					logging.warning("FSM State Value '{0}' is not of string type.".format(Val))
					return str(self.InitVal)
		# Get base type of signal----------------------------------
		BaseType=self.GetType().split('(')[0].split()[0]
		# if not standard type, check for array else return empty string
		if (not BaseType.lower().startswith("std_logic")) and not (BaseType in ["integer", "natural"]):
			if isinstance(Val, list) or isinstance(Val, tuple):
				return '('+','.join([str(x) for x in Val])+')'
			elif isinstance(self.InitVal, list) or isinstance(self.InitVal, tuple):
				return '('+','.join([str(x) for x in self.InitVal])+')'
			else: 
				return Val
		# If it's a standard type :
		if Val is None:
			if str(self.Value).lower()!="open":
				if not BaseType.lower().startswith("std_logic"):
					if isinstance(self.Value, list) or isinstance(self.Value, tuple): return self.Value[0]
					else: return self.Value
				else:
					if isinstance(self.Value, list) or isinstance(self.Value, tuple): LogicValue(self.Value[0], Size)
					else:  return LogicValue(self.Value, Size)
			else:
				if not BaseType.lower().startswith("std_logic"): return 0
				else: 
					if int(Size)<2: return "'0'"
					else: 
						if WriteBits:
							return '"{0}"'.format("0"*int(Size))
						else:
							return "(others=>'0')"
		elif isinstance(Val, Signal):
			return Val.GetValue(WriteBits=WriteBits, Vars=Vars)
		elif Val==0:
			if not BaseType.lower().startswith("std_logic"): return 0
			else: 
				if int(Size)<2: return "'0'"
				else: 
					if WriteBits:
						return '"{0}"'.format("0"*int(Size))
					else:
						return "(others=>'0')"
		else:
			try: 
				int(Val)
				if not BaseType.lower().startswith("std_logic"): return Val
				else: return LogicValue(int(Val), Size)  
			except:
				return Val
	#----------------------------------------------------------------------
	def SetInitialValue(self, InitVal):
		"""
		Change Initial value of signal.
		"""
		self.InitVal=InitVal
		return self.InitVal
	#----------------------------------------------------------------------
	def GetInitialValue(self):
		"""
		Return Initial value of signal.
		"""
		return self.InitVal
	#----------------------------------------------------------------------
	def SetIndex(self, Min, Max=None):
		"""
		Change signal name with it's VHDL indexation representation.
		"""
		#if Max!=None: 
		if Min is None:
			self.Index=None
			if self.IsArray and self.Size==1: # To appear as indexed signal ([Array 0 downto 0] must be indexed to 0)
				self.SetIndex(0)
		elif isinstance(Min, (slice,)):
			self.Index=[Min.stop, Min.start-1] # Max = start
		else:
			if Max is None: self.Index=Min
			else: self.Index=[Min, Max]
		return self
	#----------------------------------------------------------------------
	def InverseDirection(self):
		"""
		Change 'IN' into 'OUT' and conversely.
		"""
		if self.Direction=='IN': self.Direction='OUT'
		elif self.Direction=='OUT': self.Direction='IN'
		return # Do nothing if INOUT
#	#----------------------------------------------------------------------
#	def Connect(self, OtherSignal, UseValue=False):
#		if self.Direction == OtherSignal.Direction:
#			logging.error("Try to connect same signal's IO directions ({0}): skipped.".format(self.Direction))
#			return ""
#		else:
#			if self.Size==OtherSignal.Size:
#				if UseValue:
#					if self.Direction == "IN": 
#						return Connect(self.GetName(), OtherSignal.GetValue())
#					else: return Connect(OtherSignal.GetName(), self.GetValue())
#					
#				else:
#					if self.Direction == "IN": 
#						return Connect(self.GetName(), OtherSignal.GetName())
#					else: return Connect(OtherSignal.GetName(), self.GetName())
#			else:
#				logging.error("Try to connect signals of different size: skipped.")
#				return ""
	
	#----------------------------------------------------------------------
	def Connect(self, SignalX=None, UseValue=False, ValCondPairs=[]):
		"""
		Generate code for 2 signals connection (VHDL)
		"""
		if len(ValCondPairs):
			Drivers = []
			for Val, Cond in ValCondPairs:
				Drivers.append("{0} when {1}".format(Val, Cond))
			Sep = "\n"+(" "*(len(SignalA)+4)) # Align all 'when'
			Driver = Sep.join(Drivers)
		else:
			if SignalX!=None: 
				if isinstance(SignalX, Signal): 
					if UseValue: Driver = SignalX.GetValue()
					else:        Driver = SignalX.GetName()
				else: 
					Driver = self.GetValue(SignalX)
			else: 
				if UseValue: Driver = self.GetValue()
				else:        Driver = self.GetValue(self.InitVal)
		return '\n'+Associate(self.GetName(), Driver, "<=")+';'
	#----------------------------------------------------------------------
	def Parameters(self):
		"""
		return a list with parameters according to HDLEditor signal representation.
		"""
		return [self.GetName(), self.GetType(), self.InitVal, self.Size]
	#----------------------------------------------------------------------
	def Driven(self, Value): # TODO :rename
		"""
		Signal connection: Example:"S0.Driven(S1+S2)"
		"""
		return Connect(self.Name, str(Value))
	#----------------------------------------------------------------------
	def Declare(self, Constant=False, UnConstrained=False, AvailableParam=None):
		"""
		return Signal declaration code.
		"""
#		self.ReplaceConstants(Vars=AvailableParam)
		if Constant: Text="\nconstant "
		else: Text="\nsignal "
		Name = self.Name
		if self.InitVal is None:
			if Constant is True: logging.error("Constant has no initial value: bad declaration.")
			Text+="{0} : {1};".format(Name, self.GetType(UnConstrained=UnConstrained))
		else:
			InitValue=self.GetValue(self.InitVal)
			if str(self.InitVal).lower() == "open" or InitValue=="":
				if Constant is True: logging.error("Constant has no initial value: bad declaration.")
				Text+="{0} : {1};".format(Name, self.GetType(UnConstrained=UnConstrained))
			else:
				Text+="{0} : {1} := {2};".format(Name, self.GetType(UnConstrained=UnConstrained), InitValue)
		return Text
	#----------------------------------------------------------------------
	def MapConstants(self, Mapping={}, Vars={}):
		"""
		Replace generics by their mapping counterparts.
		"""
		if len(Mapping)==0 or self.GenericSize is None: return
		
		try:
			int(self.GenericSize)
			return # Integer : no replacement
		except:
			for Formal, ActualCond in Mapping.items():
				FullNames=[]
				ConcatList, Condition, Vars = ActualCond
				
				for InstName, SigName, AIndex in ConcatList:
					BaseName=SigName if InstName=='' or InstName is None else "_".join([InstName, SigName,])
					if AIndex is None:
						FullNames.append(BaseName)
					else:
						FullNames.append(BaseName+"({0})".format(AIndex))
				ActualName=" & ".join(FullNames)
				# TODO : Use condition 
#				if AIndex is None:; |, |\*|\n
				Decomposed = re.split('(\W)', self.GenericSize)#'\+|-|\*|/|\)|\(| |\n'
#				print("self.GenericSize:", self.GenericSize)
#				print("Decomposed:", Decomposed)
				for i, Item in enumerate(Decomposed):
					if Item==Formal:
						Decomposed[i]=ActualName
				self.GenericSize="".join(Decomposed)
#				print("==> self.GenericSize:", self.GenericSize)
#				if str(self.GenericSize).startswith("TaskManager"): 
#					print("Mapping:", repr(Mapping))
#					print(">", repr(self))
#					raise NameError
#				else:
#					self.GenericSize=self.GenericSize.replace(Formal, ActualName+"({0})".format(AIndex))
					
#		except:
#			# Attributes with parameters: Size, Type, InitVal, Index 
#			self.Size        = ReplaceDict(self.Size,        AvailableDict=AvailableParam)
#			self.GenericSize = ReplaceDict(self.GenericSize, AvailableDict=AvailableParam)
##			self.Type        = ReplaceDict(self.Type,        AvailableDict=AvailableParam)
#			self.InitVal     = ReplaceDict(self.InitVal,     AvailableDict=AvailableParam)
#			self.Index       = ReplaceDict(self.Index,       AvailableDict=AvailableParam)
			
#			print "AvailableParam:", AvailableParam
#			print "self.Name:", self.Name
#			print "self.Size:",self.Size
#			print "self.GenericSize:",self.GenericSize
#			return 
	#----------------------------------------------------------------------
	def AliasOf(self, Sig):
		"""
		Declare Signal as alias of another signal.
		"""
		return "\nalias {0} is {1};".format(self.Name, Sig.GetName())
	#----------------------------------------------------------------------
	def __getitem__(self, index):
#		if isinstance(index, (range,)):
#			print("index:", index)
#			input()
		if isinstance(index, int) or isinstance(index, str):
			Sig = self.Copy().SetIndex(index)
			return Sig#Signal(Sig.GetName(), self.Direction, 1, self.GetType(), self.InitVal)
		elif isinstance(index, (slice, range)):
			Start, Stop, Step = index.start, index.stop, index.step # index is a slice
			if Start==Stop:
				return self.__getitem__(Start)
			# process slice
			Sig = Signal(self.GetName(), self.Direction, str(Start)+"+1-"+str(Stop), Type=None, InitVal=0)
#			if Start<(Stop-1): 
			Sig.SetIndex(Stop, Start)
#			else: Sig.SetIndex(Start)
			return Sig
		else:
			raise TypeError("index must be int or slice")
	#----------------------------------------------------------------------
	def __add__(self, SignalName):
		"""
		Signal concatenation(if logic) or addition(if numeric): "S0 + S1"
		"""
		return self.Concatenate(SignalName)
	#----------------------------------------------------------------------
	def Concatenate(self, Sig, Vars={}):
		"""
		Return a new signal object which name is the VHDL representation
		of signals concatenation.
		"""
		NewSig = self.Copy()
		NewSig = self.SetIndex(None)
		if isinstance(Sig, Signal): 
			SignalName = Sig.GetName()
			Val1, Val2=self.GetValue(Vars=Vars), Sig.GetValue(Vars=Vars)
			try: Val1, Val2=Val1[1:].replace('"', ''), Val2[1:].replace('"', '')
			except: pass
			Template="{0:0"+str(self.GetSize(Vars=Vars))+"b}{1:0"+str(Sig.GetSize(Vars=Vars))+"b}"
			NewSig.Size=str(self.Size)+"+"+str(Sig.Size)
			NewSig.SetValue(int(Template.format(int(Val1, 2), int(Val2, 2)), 2))
		elif isinstance(Sig, str):  
			SignalName = Sig
			raise TypeError("Signal '{0}' cannot be a string object.")
		else: 
			raise TypeError("Signal '{0}' is not a string or a Signal object.")
			return None
		NewSig.Name = "{0} & {1}".format(self.GetName(), SignalName)
		return NewSig
	#---------------------------------------------------------------
	def Copy(self):
		return Signal(self)
	#---------------------------------------------------------------
	def SetTestCondition(self, TestCond='__eq__'):
		"""
		Set the test comparator type. Only used in Test() method.
		"""
		self.TestCond=OPSYMBOL_DICT[TestCond]
	#---------------------------------------------------------------
	def ConvertType(self, Value, TypeOfValue=None):
		"""
		Format value so as to fit the signal type.
		"""
		if TypeOfValue=='logic':
			if self.Type=='logic': return Value
			elif self.Type=='numeric': return "TO_INTEGER(UNSIGNED({0}))".format(Value)
			else: return Value
		elif TypeOfValue=='numeric':
			if self.Type=='logic': return Value
			elif self.Type=='numeric': return "STD_LOGIC_VECTOR(TO_UNSIGNED({0}, {1}'length))".format(Value, self.Name)
			else: return Value
		else:
			return Value
	#----------------------------------------------------------------------
	def Test(self):
		"""
		return code for value test. 
		Value attribute must be set before calling this method.
		"""
		if isinstance(self.Value, str):
			return "{0}{1}{2}".format(self.Name, self.TestCond, self.Value)
		else:
			SigSize=self.GetSize()
			if SigSize>1:
				return ('{0}{1}"{2:0'+str(SigSize)+'b}"').format(self.Name, self.TestCond, self.Value)
			else:
				if self.Value not in (0, 1):
					logging.error("{0}'s value: {1}".format(self, self.Value))
					raise TypeError
				return "{0}{1}'{2}'".format(self.Name, self.TestCond, self.Value if self.Value<2 else 1)
	#----------------------------------------------------------------------
	def __str__(self):
		"""
		Return string representation.
		"""
		return self.GetName()
	#----------------------------------------------------------------------
	def __repr__(self):
		"""
		Return object representation.
		"""
		return 'HDLEditor.Signal(Item={Item}, Direction={Direction}, Size={Size}, Type={Type}, InitVal={InitVal}, CurValue={CurValue}, IsArray={IsArray}, GenericSize={GenericSize})'.format(Item=self.Name, Direction=self.Direction, Size=self.Size, Type=self.Type, InitVal=self.InitVal, CurValue=self.Value, IsArray=self.IsArray, GenericSize=self.GenericSize)+'>'
	#----------------------------------------------------------------------
	def __len__(self):
		"""
		Return size of signal.
		"""
		return self.Size
	#---------------------------------------------------------------
	def __lt__(self, Other):
		"""
		'lower than' comparison.
		"""
		SelfName=self.GetName()
		if min(SelfName,Other.GetName())==SelfName:
			return True
		else:
			return False 
		
#=========================================================
OPSYMBOL_DICT={
		"__setitem__": None,
		"__getitem__": None,
		"__lt__":      "<",
		"__le__":      "<=",
		"__eq__":      "=",
		"__ne__":      "/=",
		"__gt__":      ">",
		"__ge__":      ">=",
		"__add__":     "+",
		"__sub__":     "-",
		"__mul__":     "*",
		"__and__":     " and ",
		"__or__":      " or ",
		"__init__":    None, # Memory init for list typed signals
}
		
##=========================================================
#OPSYMBOL_DICT={
#		"__setitem__": None,
#		"__getitem__": None,
#		"__lt__":      "<",
#		"__le__":      "<=",
#		"__eq__":      "==",
#		"__ne__":      "!=",
#		"__gt__":      ">",
#		"__ge__":      ">=",
#		"__add__":     "+",
#		"__sub__":     "-",
#		"__mul__":     "*",
#		"__and__":     "&",
#		"__or__":      "|",
#		"__init__":    None, # Memory init for list typed signals
#}
	
#======================================================================
def Connect(SignalA, SignalB=None, ValCondPairs=[], Size=1):
	"""
	Generate code for 2 signals connection (VHDL)
	"""
	if len(ValCondPairs):
		Drivers = []
		for Val, Cond in ValCondPairs:
			Drivers.append("{0} when {1}".format(Val, Cond))
		Sep = "\n"+(" "*(len(SignalA)+4)) # Align all 'when'
		Driver = Sep.join(Drivers)
	else:
		if SignalB: Driver = SignalB
		else: Driver = LogicValue(0, Size)
	return '\n'+Associate(SignalA, Driver, "<=")+';'
	

#======================================================================
def NormalizeText(text):
	"""
	Return a normalized format for the input text.
	"""
	return unicodedata.normalize('NFKD', str(text)).encode('ASCII', 'ignore')
	
#============================================================================
def GetTBProcess(DUTName):
	"""
	Return VHDL code for the read of textio stimuli file.
	"""
	return """
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
TEST: process
	--file TestFile : text is in "./stimValues.txt";
	file TestFile : text open read_mode is "./stimValues.txt";
	variable L           : line;
	variable TimeVector  : time;
	variable R           : integer;--real
	variable good_number : boolean := True;
	variable index       : integer;
	variable TooMuchStim : boolean := True;

begin  -- process Test

	--WRITE_STRING (OUTPUT, "*** {0} test ***");
	write(output, "*** Start {0} test ***");

	while not endfile(TestFile) loop
		readline(TestFile, L);
		--writeline(output, L);
	
		read(L, R, GOOD => good_number);-- read the time from the beginning of the line
		if not good_number then
			write(output, "Skip line:");
			writeline(output, L);
		end if;
		next when not good_number;-- skip the line if it doesn't start with a number

		TimeVector := natural(R) * 1 ns; -- convert real number to time
		if (now < TimeVector) then -- wait until vector time
			wait for TimeVector - now;
			write(output, "Time : " & integer'image(R));
		end if;
		index := NbStimuli-1;
		TooMuchStim := False;
		--write(output, "NbStimuli=" & integer'image(NbStimuli));

		--For each caracter in line:
		for i in L'range loop
			if index<0 then -- wait until vector time
				if L(i)='0' or  L(i)='1' or L(i)='H' or  L(i)='L' or L(i)='X' then
					write(output, "Error parsing line:");
					writeline(output, L);
					assert false report "Given stimuli bit number exceeds the number of stimuli signals." severity ERROR;
					exit;
				end if;
			end if;
			--write(output, "index : " & integer'image(index));
			--write(output, "Stimuli length : " & integer'image(Stimuli'length));
			case L(i) is
				when '0' => -- Drive 0
					Stimuli(index) <= '0';
				when '1' => -- Drive 1
					Stimuli(index) <= '1';
				when 'H' => -- Test for 1
					assert Stimuli(index) = '1';
				when 'L' => -- Test for 0
					assert Stimuli(index) = '0';
				when 'X' => -- Don't care
					null;
				when ' ' | HT => -- Skip white space
					next;
				when others =>
					-- Illegal character
					assert false report "Illegal char in vector file: " & L(i);
				exit;
			end case;
			index := index-1;
		end loop;  -- end of line

	end loop;  -- end of file

assert false report "*** Test complete ***";
wait;

end process TEST;""".format(DUTName)

#======================================================================
def ReplaceDict(Item, AvailableDict={}):
	"""
	Replace each occurence of a parameter by its driver.
	"""
	for Key, Val in AvailableDict.items(): 
		if Item is None or isinstance(Item, (int, float)): 
			pass #return Item
		else:
			if isinstance(Item, (list, tuple)): 
				pass
			else:
				Item=Item.replace(Key, str(AvailableDict[Key]))
	return Item
	
#======================================================================

# ====================     START OF MODULE TEST  =====================
if (__name__ == "__main__"):

	HDLTopFile=os.path.abspath("./HDLEditor/NOC.vhd")
	toVHDL.name="NOC"
	toVHDL(*HDL2myHDL(HDLTopFile))


















