################################################################################
##
## Register map generation tool
##
## Copyright (C) 2018 Ondrej Ille <ondrej.ille@gmail.com>
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this SW component and associated documentation files (the "Component"),
## to deal in the Component without restriction, including without limitation
## the rights to use, copy, modify, merge, publish, distribute, sublicense,
## and/or sell copies of the Component, and to permit persons to whom the
## Component is furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included in
## all copies or substantial portions of the Component.
##
## THE COMPONENT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
## AUTHORS OR COPYRIGHTHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
## FROM, OUT OF OR IN CONNECTION WITH THE COMPONENT OR THE USE OR OTHER DEALINGS
## IN THE COMPONENT.
##
###############################################################################

###############################################################################
##
##   Register map generator. Generates synthesizable VHDL entity from IP-XACT
##   Address Map. Uses constants generated by Address map generator.
##
##	Revision history:
##		7.10.2018	First implementation
##
################################################################################

import math
import os
import sys
import copy

from abc import ABCMeta, abstractmethod
from pyXact_generator.ip_xact.addr_generator import IpXactAddrGenerator

from pyXact_generator.gen_lib import *

from pyXact_generator.languages.gen_vhdl import VhdlGenerator
from pyXact_generator.languages.declaration import LanDeclaration

class VhdlRegMapGenerator(IpXactAddrGenerator):

	# HDL generator object, can be VHDL, can be SV
	hdlGen = None

	# Paths of VHDL templates
	template_sources = {}
	template_sources["addr_dec_template_path"] = "templates/address_decoder.vhd"

	template_sources["reg_rw_template_path"] = "templates/memory_reg_rw.vhd"
	template_sources["reg_rw_lock_template_path"] = "templates/memory_reg_rw_lock.vhd"
	template_sources["reg_os_template_path"] = "templates/memory_reg_os.vhd"
	template_sources["reg_os_lock_template_path"] = "templates/memory_reg_os_lock.vhd"

	template_sources["data_mux_template_path"] = "templates/data_mux.vhd"
	template_sources["mem_bus_template_path"] = "templates/memory_bus.vhd"
	template_sources["access_signaller_template_path"] = "templates/access_signaler.vhd"
	template_sources["cmn_reg_map_pkg"] = "templates/cmn_reg_map_pkg.vhd"


	of_pkg = None

	def __init__(self, pyXactComp, memMap, wrdWidth):
		super().__init__(pyXactComp, memMap, wrdWidth)

		# By default VHDL generator is used
		self.hdlGen = VhdlGenerator()


	def set_hdl_generator(self, hdlGen):
		"""
		Set HDL generator.
		"""
		self.hdlGen = hdlGen;


	def commit_to_file(self):
		"""
		Commit the generator output into the output file.
		"""
		for line in self.hdlGen.out :
			self.of.write(line)

		self.hdlGen.out = []


	def create_reg_ports(self, block, signDict):
		"""
		Creates declarations for Output/Input ports of an entity which
		correspond to values Written / Read  to / from registers.
		Declarations have following format:
			signal <block_name>_in   : in <block_name>_in_t
			signal <block_name>_out  : in <block_name>_out_t
		Declarations are appended to signDict dictionary.
		"""
		if (not checkIsDict(signDict)):
			return

		reg_ports = ["out", "in"]

		for reg_port in reg_ports:
			port = LanDeclaration(block.name + "_" + reg_port, value=None)
			port.direction = reg_port
			port.type = block.name + "_" + reg_port + "_t"
			port.bitWidth = 0
			port.specifier = "signal"
			signDict[port.name] = port


	def create_wr_reg_sel_decl(self, block, signDict):
		"""
		Create declaration of register selector signal for writable
		registers within a memory block. Width of register selector is number of
		words within a block which contain at least one writable register.
		"""
		signDict["reg_sel"] = LanDeclaration("reg_sel", value = None)
		signDict["reg_sel"].type = "std_logic"
		signDict["reg_sel"].specifier = "signal"
		signDict["reg_sel"].bitWidth = self.calc_blk_wrd_count(block)


	def calc_addr_vect_value(self, block):
		"""
		Calculate address vector value for address decoder for reach register
		word.
		"""
		vect_val = ""
		addr_entry_width = self.calc_wrd_address_width(block)

		# Check if register is present on a given word, if yes, append it to the
		# vector.
		[low_addr, high_addr] = self.calc_blk_wrd_span(block)
		high_addr += self.wrdWidthByte

		for wrd_addr in range(low_addr, high_addr, self.wrdWidthByte):
			regs_in_wrd = self.get_regs_from_word(wrd_addr, block)

			# Word with no registers can be skipped, nothing is appended to
			# address vector
			if (not regs_in_wrd):
				continue;

			# Append address vector value
			shifted_val = int(wrd_addr / self.wrdWidthByte)
			vect_val = str("{:06b}".format(shifted_val)) + vect_val

		return vect_val


	def create_addr_vect_decl(self, block, signDict):
		"""
		Create declaration of Address vector constant which is an input to
		Address decoder.
		"""
		signDict["addr_vect"] = LanDeclaration("addr_vect", value = None)
		signDict["addr_vect"].type = "std_logic"
		signDict["addr_vect"].specifier = "constant"
		signDict["addr_vect"].value = self.calc_addr_vect_value(block)

		# LSBs are cut
		addr_vect_size = self.calc_blk_wrd_count(block) * \
							self.calc_wrd_address_width(block)
		signDict["addr_vect"].bitWidth = addr_vect_size


	def create_read_data_mux_in_decl(self, block, signDict):
		"""
		Create declaration of read data multiplexor input signal. Length of
		read data mux input covers the minimum necessary length to cover
		all words with readable registers.
		"""
		signDict["read_data_mux_in"] = LanDeclaration("read_data_mux_in", value = None)
		signDict["read_data_mux_in"].type = "std_logic"

		[low_addr, high_addr] = self.calc_blk_wrd_span(block, ["read"])
		high_addr += self.wrdWidthByte
		signDict["read_data_mux_in"].bitWidth = (high_addr - low_addr) * 8;
		signDict["read_data_mux_in"].specifier = "signal"


	def create_read_data_mask_n_decl(self, block, signDict):
		"""
		Create declaration of Read data mask signal for Read data multiplexor.
		"""
		signDict["read_data_mask_n"] = LanDeclaration("read_data_mask_n", value = None)
		signDict["read_data_mask_n"].type = "std_logic"
		signDict["read_data_mask_n"].bitWidth = self.wrdWidthBit
		signDict["read_data_mask_n"].specifier = "signal"


	def create_write_data_int_decl(self, block, signDict):
		"""
		Create declaration for internal record with data written to writable
		registers.
		"""
		name = block.name + "_out"
		signDict[name + "_i"] = LanDeclaration(name + "_i", value = None)
		signDict[name + "_i"].type = name + "_t"
		signDict[name + "_i"].specifier = "signal"


	def create_read_mux_ena_int_decl(self, signDict):
		"""
		Create declaration for read data multiplexor enable. This allows keeping
		or clearing read data signal after data were read.
		"""
		signDict["read_mux_ena"] = LanDeclaration("read_mux_ena", value = None)
		signDict["read_mux_ena"].type = "std_logic"
		signDict["read_mux_ena"].bitWidth = 1
		signDict["read_mux_ena"].specifier = "signal"


	def create_write_en_int_decl(self, signDict):
		"""
		Create declaration of internal write enable signal gated by byte enables
		"""
		signDict["read_mux_ena"] = LanDeclaration("write_en", value = None)
		signDict["read_mux_ena"].type = "std_logic"
		signDict["read_mux_ena"].bitWidth = self.wrdWidthByte
		signDict["read_mux_ena"].specifier = "signal"


	def create_internal_decls(self, block, signDict):
		"""
		Create declarations of internal signals of architecture of register
		memory block. Following declarations are created:
			- Write selector signal for all writable registers
			- Address vector input to address decoder
			- Read data multiplexor input vector.
			- Read data mask signal from byte enable signals
            - Internal signal for output register structure
		"""
		if (not checkIsDict(signDict)):
			return;

		# Create output of address decoder
		self.create_wr_reg_sel_decl(block, signDict)

		# Create address vector input to address decoder
		self.create_addr_vect_decl(block, signDict)

		# Create data mux input signal (long logic vector)
		self.create_read_data_mux_in_decl(block, signDict)

		# Create data mask signal for read multiplextor
		self.create_read_data_mask_n_decl(block, signDict)

		# Create internal signal for output register structure (output values
		# of writable registers)
		self.create_write_data_int_decl(block, signDict)

		# Create declaration of read data clear signal
		self.create_read_mux_ena_int_decl(signDict)

		# Create declaration of internal write enable
		self.create_write_en_int_decl(signDict)


	def create_read_wrd_from_regs(self, regs_in_wrd, block, is_last):
		"""
		Create single read word input to read data multiplexor input. Readable
		registers are implemented.
		"""
		read_wrd = ""

		i = self.wrdWidthBit - 1
		while (i >= 0):
			is_padding = True
			index_placed = False
			for reg in regs_in_wrd:
				# Skip registers which are not readable
				if (not (self.reg_has_access_type(reg, ["read"]))):
					continue

				for field in sorted(reg.field, key=lambda a: a.bitOffset):
					field_low = field.bitOffset + ((reg.addressOffset % 4) * 8)
					field_high = field.bitOffset + ((reg.addressOffset % 4) * 8) + field.bitWidth - 1
					if field_low == i:
						if self.reg_is_access_type(reg, ["read-write"]):
							suffix = "_out_i."
						else:
							suffix = "_in."
						read_wrd += str("	" + block.name + suffix + reg.name + "_" + field.name).lower()
						index_placed = True

					# Search if the bit has no field
					for ifield in sorted(reg.field, key=lambda a: a.bitOffset):
						if ((i >= field_low) and (i <= field_high)):
							is_padding = False

			if is_padding:
				read_wrd += "	'0'"
				index_placed = True

			if (index_placed):
				if (i > 0 or not is_last):
					read_wrd += "	&\n"
				else:
					read_wrd += "\n"
			i -= 1;

		return read_wrd


	def create_read_data_mux_in(self, block):
		"""
		Create driver for read data multiplexor input signal. Read data
		multiplexor is a long vector with read data concatenated to
		long std_logic vector.
		"""
		self.hdlGen.write_comment("Read data driver", gap = 2)
		self.hdlGen.push_parallel_assignment("read_data_mux_in")
		self.hdlGen.wr_line("\n")

		# Check each word in the memory block, Start from highest address
		# since highest bits in std_logic_vector correspond to highest
		# address!
		[low_addr, high_addr] = self.calc_blk_wrd_span(block, ["read"])
		high_addr += self.wrdWidthByte

		# TODO: This could be written with concatenation!!
		for addr in reversed(range(low_addr, high_addr, self.wrdWidthByte)):

			# Create comment with word address
			self.hdlGen.write_comment("Adress:" + str(addr), gap=4, small=True)

			# Search for all registers which are also "read" in given word
			regs_in_wrd = self.get_regs_from_word(addr, block)
			is_last = False
			if (addr == low_addr):
				is_last = True
			wrd_value = self.create_read_wrd_from_regs(regs_in_wrd, block, is_last)

			self.hdlGen.wr_line(wrd_value)

			if (addr == low_addr):
				break
			self.hdlGen.wr_line("\n")

		self.hdlGen.commit_append_line(1)
		self.hdlGen.wr_line("\n")


	def calc_addr_indices(self, block):
		"""
        Calculates low and high index of address vector necessary for addressing
        given memory block. Each word is addressed and LSBs of address to address
        within a word is truncated.
		"""
		addr_lind = self.calc_addr_width_from_size(self.wrdWidthByte)
		addr_hind = self.calc_addr_width_from_size(block.range) - 1

		return [addr_hind, addr_lind]


	def create_write_en_assign(self):
		"""
		"""
		self.hdlGen.create_signal_connection("write_en",
						"be when (write = '1' and cs = '1') else (others => '0')", gap=4)
		self.hdlGen.wr_line("\n")


	def create_addr_decoder(self, block):
		"""
        Create instance of address decoder for writable registers.
		"""
		path = os.path.join(ROOT_PATH, self.template_sources["addr_dec_template_path"])

		addr_dec = self.hdlGen.load_entity_template(path)
		addr_dec.isInstance = True
		addr_dec.value = addr_dec.name.lower() + "_" + block.name.lower() + "_comp"
		addr_dec.gap = 2

		# Connect generics
		addr_dec.generics["address_width"].value = self.calc_wrd_address_width(block)
		addr_dec.generics["address_entries"].value = self.calc_blk_wrd_count(block)
		addr_dec.generics["addr_vect"].value = "ADDR_VECT"
		addr_dec.generics["registered_out"].value = "false"

		# Connect ports
		addr_dec.ports["clk_sys"].value = "clk_sys"
		addr_dec.ports["res_n"].value = "res_n"

		addr_indices = self.calc_addr_indices(block)
		addr_str =  "address(" + str(addr_indices[0])
		addr_str += " downto " + str(addr_indices[1]) + ")"
		addr_dec.ports["address"].value = addr_str

		addr_dec.ports["addr_dec"].value = "reg_sel"

		addr_dec.ports["enable"].value = "cs"

        # Create instance of a component
		self.hdlGen.write_comment("Write address to One-hot decoder", gap = 4)
		self.hdlGen.format_entity_decl(addr_dec)

		self.hdlGen.create_comp_instance(addr_dec)


	def calc_reg_rstval_mask(self, reg):
		return super().calc_reg_rstval_mask(reg)


	def calc_reg_byte_enable_vector(self, reg):
		"""
		Create byte enable vector for a register. Position of register within
		a memory word is considered.
		"""
		l_be_ind = reg.addressOffset % 4
		h_be_ind = l_be_ind + int(reg.size / 8) - 1
		return self.hdlGen.format_vector_range("be", h_be_ind, l_be_ind)


	def fill_reg_inst_generics(self, reg, field, reg_inst):
		"""
		Fill Generic values of VHDL register instance from IP-XACT register
		object.
		"""
		reg_inst.generics["data_width"].value = field.bitWidth

		#if (field.bitWidth == 1):
		#	reg_inst.generics["reset_value"].value = "'" + str(field.reset_value) + "'"
		#else:
		rst_rem = field.reset_value
		i = 0
		rst_str = ""
		while i < field.bitWidth:
			rst_str = str(rst_rem % 2) + rst_str
			rst_rem = rst_rem >> 1
			i += 1
		reg_inst.generics["reset_value"].value = '"' + rst_str + '"'


	def fill_reg_ports(self, block, reg, field, reg_inst):
		"""
		Fill ports for register instance from IP-XACT register object
		"""
		reg_inst.ports["clk_sys"].value = "clk_sys"
		reg_inst.ports["res_n"].value = "res_n"

		# If register has single field, do not append field name, most
		# likely the same as name of the register!
		#if (len(reg.field) == 1):
		#	reg_name = reg.name
		#else:

		reg_name = reg.name + "_" + field.orig_name
		reg_value = block.name + "_out_i." + reg_name

		if field.bitWidth == 1:
			reg_inst.ports["reg_value"].name += "(0)"

		if field.is_slice:
			if field.bitWidth == 1:
				range_str = "({})".format(field.bit_pos_low)
			else:
				range_str = "({} downto {})".format(field.bit_pos_high, field.bit_pos_low)
			reg_value += range_str

		reg_inst.ports["reg_value"].value = reg_value.lower()

		# Calculate data input indices within a memory word
		start_bit = (reg.addressOffset % 4) * 8
		l_ind = start_bit + field.bitOffset
		h_ind = start_bit + field.bitWidth + field.bitOffset - 1
		reg_inst.ports["data_in"].value = "w_data({} downto {})".format(h_ind, l_ind)

		# Calculate write enable position
		write_en_bit = (reg.addressOffset % 4) + int(field.bitOffset/8)
		reg_inst.ports["write"].value = "write_en({})".format(write_en_bit)

		reg_sel_index = self.get_wrd_index(block, reg) - 1
		reg_inst.ports["cs"].value = self.hdlGen.format_vector_index("reg_sel", reg_sel_index)

		# Connect lock signal to lockable registers
		if (self.get_reg_lock(reg)[0] == "true"):
			reg_inst.ports["lock"].value = self.get_reg_lock(reg)[2]


	def split_reg_fields(self, reg):
		"""
		Split register fields so they do not span multiple bytes in memory
		"""
		split_fields = []
		#print("Processing register: {}".format(reg.name))
		for field in sorted(reg.field, key=lambda a: a.bitOffset):
			low_index = field.bitOffset
			high_index = field.bitOffset + field.bitWidth - 1
			if (field.resets == None):
				reset_remainder = 0
			else:
				reset_remainder = int(field.resets.reset.value)

			i = int(low_index / 8) + 1
			slice_cnt = 1
			width_so_far = 0
			while (int(low_index/8) != int(high_index/8)):
				new_field = copy.copy(field)
				new_field.name += "_slice_{}".format(slice_cnt)
				new_field.bitOffset = low_index
				new_field.bitWidth = i * 8 - low_index

				new_field.is_slice = True
				new_field.bit_pos_low = width_so_far
				new_field.bit_pos_high = width_so_far + new_field.bitWidth - 1

				new_field.reset_value = reset_remainder & int(2 ** new_field.bitWidth - 1)
				new_field.orig_name = field.name
				reset_remainder = reset_remainder >> new_field.bitWidth

				low_index = int(i * 8)
				i += 1
				slice_cnt += 1
				width_so_far += new_field.bitWidth

				#print("Stripping field {}:".format(new_field.name))
				#print("		OFFSET: {} WIDTH: {} RESET VAL: {}".format(new_field.bitOffset, new_field.bitWidth, new_field.reset_value))
				#print("")
				split_fields.append(new_field)

			new_field = copy.copy(field)
			if (slice_cnt > 1):
				new_field.name += "_slice_{}".format(slice_cnt)
				new_field.is_slice = True
			else:
				new_field.is_slice = False
			new_field.orig_name = field.name
			new_field.bitOffset = low_index
			new_field.bitWidth = high_index - low_index + 1

			new_field.bit_pos_low = width_so_far
			new_field.bit_pos_high = width_so_far + new_field.bitWidth - 1

			new_field.reset_value = reset_remainder

			split_fields.append(new_field)

			#print("Adding field {}:".format(new_field.name))
			#print("		OFFSET: {} WIDTH: {} RESET VAL: {}".format(new_field.bitOffset, new_field.bitWidth, new_field.reset_value))
			#print("")

		return split_fields


	def create_reg_instance(self, block, reg):
		"""
		Create register instance from IP-XACT register object. If "isPresent" property
        is set, parameter name is searched in IP-XACT input and it's name is used
        as generic condition for register presence.
		"""
		# Write conditional generic expression if register isPresent property
		# depends on IP-XACT Parameter
		if (reg.isPresent != ""):
			paramName = self.parameter_lookup(reg.isPresent)
			self.hdlGen.create_if_generate(reg.name + "_present_gen_t",
				paramName.upper(), "true", gap=4)

		# Split fields if they span multiple bytes to at most 8-bit register instances
		split_fields = self.split_reg_fields(reg)

		for field in split_fields:

			# Load register template path and create basic instance
			if (self.get_reg_lock(reg)[0] == "true"):
				if (field.modifiedWriteValue == "clear"):
					path = os.path.join(ROOT_PATH, self.template_sources["reg_os_lock_template_path"])
				else:
					path = os.path.join(ROOT_PATH, self.template_sources["reg_rw_lock_template_path"])
			else:
				if (field.modifiedWriteValue == "clear"):
					path = os.path.join(ROOT_PATH, self.template_sources["reg_os_template_path"])
				else:
					path = os.path.join(ROOT_PATH, self.template_sources["reg_rw_template_path"])

			reg_inst = self.hdlGen.load_entity_template(path)
			reg_inst.isInstance = True
			reg_inst.intType = "entity"
			reg_inst.value = reg.name.lower() + "_" + field.name.lower() + "_reg_comp"

			self.hdlGen.write_comment(reg.name.upper() + "[" + field.name.upper() + "]", gap = 4)

			# Fill generics of reg map component
			self.fill_reg_inst_generics(reg, field, reg_inst)

			# Fill Ports of reg map component
			self.fill_reg_ports(block, reg, field, reg_inst)

			# Format register instances and print it
			self.hdlGen.format_entity_decl(reg_inst)
			self.hdlGen.create_comp_instance(reg_inst)


		# Pop end of generate statement determined by isPresent property. Append
		# dummy drivers for case when parameter is false
		if (reg.isPresent != ""):
			self.hdlGen.commit_append_line(1)
			self.hdlGen.wr_line("\n")
			self.hdlGen.create_if_generate(reg.name + "_present_gen_f",
				paramName.upper(), "false", gap=4)

			#rst_val = self.calc_reg_rstval_mask(reg)
			for field in sorted(reg.field, key=lambda a: a.bitOffset):
				# TODO: This is hard-coded for current CTU CAN FD!
				#		Takes into acocunt only FILTER registers, not arbitrary reset value!
				self.hdlGen.create_signal_connection(
					(block.name + "_out_i." + reg.name + "_" + field.name).lower(), "(others => '0')", gap = 8)

			self.hdlGen.commit_append_line(1)
			self.hdlGen.wr_line("\n")


	def fill_access_signaller_generics(self, reg, signaller_inst):
		"""
		Fill generics for VHDL access signaller instance from IP-XACT register
		object.
		"""
		signaller_inst.generics["data_width"].value = reg.size

		# Read signalling capability
		if (self.is_reg_read_indicate(reg)):
			signaller_inst.generics["read_signalling"].value = True
		else:
			signaller_inst.generics["read_signalling"].value = False

		# Mark read signalling as combinational value!
		signaller_inst.generics["read_signalling_reg"].value = False

		# Write signalling capability, set signalling as registered to have
		# the signal in the same clock cycle as new data are written to the
		# register!
		if (self.is_reg_write_indicate(reg)):
			signaller_inst.generics["write_signalling"].value = True
			signaller_inst.generics["write_signalling_reg"].value = True
		else:
			signaller_inst.generics["write_signalling"].value = False
			signaller_inst.generics["write_signalling_reg"].value = False


	def fill_access_signaller_ports(self, block, reg, signaller_inst):
		"""
		Fill ports for VHDL access signaller instance from IP-XACT register
		object.
		"""
		signaller_inst.ports["clk_sys"].value = "clk_sys"
		signaller_inst.ports["res_n"].value = "res_n"

		# Get word index from address decoder
		reg_sel_index = self.get_wrd_index(block, reg) - 1
		signaller_inst.ports["cs"].value = \
			self.hdlGen.format_vector_index("reg_sel", reg_sel_index)

		# Connect memory bus signals
		signaller_inst.ports["read"].value = "read"
		signaller_inst.ports["write"].value = "write"
		signaller_inst.ports["be"].value = self.calc_reg_byte_enable_vector(reg)

		# Connect write access signalling
		wr_signal = "open"
		if (self.is_reg_write_indicate(reg)):
			wr_signal = (block.name + "_out_i." + reg.name + "_write").lower()
		signaller_inst.ports["write_signal"].value = wr_signal

		# Connect read access signalling
		rd_signal = "open"
		if (self.is_reg_read_indicate(reg)):
			rd_signal = (block.name + "_out_i." + reg.name + "_read").lower()
		signaller_inst.ports["read_signal"].value = rd_signal


	def create_access_signaller(self, block, reg):
		"""
		Create access signaller components for registers which have this feature
		enabled.
		"""
		path = os.path.join(ROOT_PATH, self.template_sources["access_signaller_template_path"])
		signaller_inst = self.hdlGen.load_entity_template(path)
		signaller_inst.isInstance = True
		signaller_inst.intType = "entity"
		signaller_inst.value = reg.name.lower() + "_access_signaller_comp"

		# Fill generic values of access signaller
		self.fill_access_signaller_generics(reg, signaller_inst)

		# Fill ports of access signaller
		self.fill_access_signaller_ports(block, reg, signaller_inst)

		self.hdlGen.write_comment(reg.name.upper() + " access signallization", gap = 4)

		# Create component of signaller
		self.hdlGen.format_entity_decl(signaller_inst)
		self.hdlGen.create_comp_instance(signaller_inst)


	def create_write_reg_instances(self, block):
		"""
		Create VHDL instance for each writable register in a memory block.
		"""
		for i,reg in enumerate(sorted(block.register, key=lambda a: a.addressOffset)):

			# Create register instances for writable registers
			if (self.reg_has_access_type(reg, ["write"])):
				self.create_reg_instance(block, reg)

			# Create access signalling for registers which have access signalling enabled
			if (self.is_reg_write_indicate(reg) or self.is_reg_read_indicate(reg)):
				self.create_access_signaller(block, reg)


	def create_read_data_mux_instance(self, block):
		"""
        Create instance of Read data multiplexor.
		"""
		path = os.path.join(ROOT_PATH, self.template_sources["data_mux_template_path"])

		# Load data mux template
		data_mux = self.hdlGen.load_entity_template(path)
		data_mux.isInstance = True
		data_mux.value = (data_mux.name + "_"+ block.name + "_comp").lower()

		# FIll generic values
		data_mux.generics["data_out_width"].value = self.wrdWidthBit

		[low_addr, high_addr] = self.calc_blk_wrd_span(block, ["read"])
		high_addr += self.wrdWidthByte
		data_mux.generics["data_in_width"].value = (high_addr - low_addr) * 8;

		data_mux_indices = self.calc_addr_indices(block)
		data_mux_sel_width = data_mux_indices[0] - data_mux_indices[1] + 1
		data_mux.generics["sel_width"].value = data_mux_sel_width

		data_mux.generics["registered_out"].value = "registered_read".upper()

		# Connect ports
		data_mux.ports["clk_sys"].value = "clk_sys"
		data_mux.ports["res_n"].value = "res_n"

		addr_indices = self.calc_addr_indices(block)
		addr_str = self.hdlGen.format_vector_range("address", addr_indices[0], addr_indices[1])
		data_mux.ports["data_selector"].value = addr_str

		data_mux.ports["data_in"].value = "read_data_mux_in"
		data_mux.ports["data_mask_n"].value = "read_data_mask_n"
		data_mux.ports["data_out"].value = "r_data"

		# Enable data loading
		data_mux.ports["enable"].value = "'1'";

		self.hdlGen.write_comment("Read data multiplexor", gap=4)
		self.hdlGen.format_entity_decl(data_mux)
		self.hdlGen.create_comp_instance(data_mux)


	def create_read_data_mask_driver(self):
		"""
		Create driver for read data mask signal from byte enable inputs of memory
		bus.
		"""
		self.hdlGen.write_comment("Read data mask - Byte enables", gap = 4)
		self.hdlGen.push_parallel_assignment(signalName = "read_data_mask_n", gap = 4)

		wrd_line = ""
		byte_lst = []
		for byte in range(self.wrdWidthByte - 1, -1, -1):
			be_ind = self.hdlGen.format_vector_index("be", byte)
			for x in range(0,8):
				byte_lst.append(be_ind)
				byte_lst[-1] += " "
				if (x == 0):
					byte_lst[-1] = "\n      " + byte_lst[-1]

		self.hdlGen.wr_line(self.hdlGen.format_concatenation(byte_lst))
		self.hdlGen.commit_append_line(1)
		self.hdlGen.wr_line("\n")


	def create_reg_cond_generics(self, block, entity):
		"""
		Add conditional generic definitions into entity declaration. Parameter
		"isPresent" of each IP-XACT register is added as generic boolean input.
		Parameter look-up is performed for each found parameter.
		"""
		for reg in block.register:
			if (reg.isPresent != ""):
				paramName = self.parameter_lookup(reg.isPresent)
				entity.generics[paramName] = LanDeclaration(paramName, value = 0)
				entity.generics[paramName].value = "true"
				entity.generics[paramName].type = "boolean"
				entity.generics[paramName].specifier = "constant"


	def create_reg_block_template(self, block):
		"""
		Load memory bus entity template, add ports for register inputs, outputs.
		Create declaration of register block entity.
		"""
		# Load memory bus template and create entity definition
		path = os.path.join(ROOT_PATH, self.template_sources["mem_bus_template_path"])
		entity = self.hdlGen.load_entity_template(path)
		entity.intType = "entity"
		entity.isInstance = False
		entity.name = block.name.lower() + "_reg_map"

		# Add ports for register values
		self.create_reg_ports(block, entity.ports)

		# Add generics for conditionally defined components
		self.create_reg_cond_generics(block, entity)

		# Format entity declarations to look nice
		self.hdlGen.format_decls(entity.ports, gap=2, alignLeft=True,
					alignRight=False, alignLen=30, wrap=False)
		self.hdlGen.format_decls(entity.generics, gap=2, alignLeft=True,
					alignRight=False, alignLen=30, wrap=False)

		self.hdlGen.create_comp_instance(entity)
		self.hdlGen.commit_append_line(1)

		return entity


	def create_write_reg_record_driver(self, block):
		"""
		Create driver for write register record. Internal signal is connected
		to output port.
		"""
		dest = block.name + "_out"
		src = dest + "_i"
		self.hdlGen.create_signal_connection(dest, src, gap = 4)


	def create_reg_access_cover_point(self, block, reg, acc_type):
		"""
		Create cover point for write/read to/from a register.
		"""
		# Get index of memory word for the register
		reg_sel_index = self.get_wrd_index(block, reg) - 1

		# Calcuate byte enable indices
		l_be_ind = reg.addressOffset % 4
		h_be_ind = l_be_ind + int(reg.size / 8) - 1

		be_lst = []
		for i in range(l_be_ind, h_be_ind + 1):

			be_lst.append(self.hdlGen.format_logic_op(
						    [self.hdlGen.format_vector_index("be",i),
							 self.hdlGen.format_bin_const("1")],
							 self.hdlGen.LogicOp.OP_COMPARE))

		be_str = self.hdlGen.format_logic_op(be_lst, self.hdlGen.LogicOp.OP_OR)

		op_lst = []
		op_lst.append(self.hdlGen.format_logic_op(
						["cs", self.hdlGen.format_bin_const("1")],
						self.hdlGen.LogicOp.OP_COMPARE))
		op_lst.append(self.hdlGen.format_logic_op(
						[acc_type, self.hdlGen.format_bin_const("1")],
						self.hdlGen.LogicOp.OP_COMPARE))
		op_lst.append(self.hdlGen.format_logic_op(
						[self.hdlGen.format_vector_index("reg_sel", reg_sel_index),
						 self.hdlGen.format_bin_const("1")],
						self.hdlGen.LogicOp.OP_COMPARE))
		op_lst.append(be_str)
		sequence = self.hdlGen.format_logic_op(op_lst, self.hdlGen.LogicOp.OP_AND)
		self.hdlGen.write_assertion("{}_{}_access_cov".format(reg.name.lower(), acc_type),
							   "cover", sequence);

		self.hdlGen.wr_nl()


	def create_reg_access_cover_points(self, block):
		"""
		Create cover points to monitor functional coverage within the
		generated block. Following points are created:
			1. Write cover point for each writable register.
			2. Read cover point for each readable register.
		"""
		# Add comments for readabiliy
		self.hdlGen.write_comment("<RELEASE_OFF>", gap = 4, small=True)
		self.hdlGen.write_comment("Functional coverage", gap = 4)

		# Specify clock for PSL
		if (type(self.hdlGen) == VhdlGenerator):
			self.hdlGen.write_comment(" psl default clock is " \
				"rising_edge(clk_sys);", gap = 4, small=True)

		# Go through the registers
		for i,reg in enumerate(sorted(block.register, key=lambda a: a.addressOffset)):

			# Create write psl coverage for every writable register
			if (self.reg_has_access_type(reg, ["write"])):
				self.create_reg_access_cover_point(block, reg, "write");

			# Create read psl coverage for every readable register
			if (self.reg_has_access_type(reg, ["read"])):
				self.create_reg_access_cover_point(block, reg, "read");

		# Add release ON
		self.hdlGen.write_comment("<RELEASE_ON>", gap = 4, small=True)


	def create_read_data_mux_ena(self):
		"""
		Create driver for read data multiplexor enable signal. If read data
		should be cleared after transaction, enable is constantly at logic 1,
		thus next cycle will data will be cleared, read mux  output flop is
		permanently enabled. If read data should not be cleared, flop is
		enabled only by new transaction.
		"""

		self.hdlGen.write_comment("Read data multiplexor enable ", gap = 4)

		# Read data should be kept, enable is driven by read signal which is
		# active for each read transaction
		self.hdlGen.create_if_generate(name="read_data_keep_gen",
				condition="clear_read_data".upper(), value="false", gap = 4)

		self.hdlGen.create_signal_connection(result="read_mux_ena",
												driver="read and cs", gap=8)

		self.hdlGen.commit_append_line(1)
		self.hdlGen.wr_line("\n")

		# Read data should be cleared, enable is constant 1, thus at next cycle
		# all byte enables will be zero and all zeroes will propagate on
		# outputs.
		self.hdlGen.create_if_generate(name="read_data_clear_gen",
				condition="clear_read_data".upper(), value="true", gap = 4)

		# Note that this approach will clock register value to the data mux
		# output also when write is executed to this register. We don't
		# mind this, since register reads has no side effects! Side effects
		# are implemented via access_signallers and thus choosing the
		# register value by read data mux even when it is not needed is
		# sth we don't mind.
		self.hdlGen.create_signal_connection(result="read_mux_ena",
												driver="'1'", gap=8)

		self.hdlGen.commit_append_line(1)
		self.hdlGen.wr_line("\n")


	def write_reg_block(self, block):
		"""
        Create register block in VHDL from IP-XACT memory block object.
		"""

		# Write file introduction
		self.hdlGen.wr_nl()

		self.hdlGen.write_comment("Register map implementation of: " +
				block.name, gap = 0)
		self.hdlGen.write_gen_note()
		self.hdlGen.wr_nl()

		if (type(self.hdlGen) == VhdlGenerator):
			self.hdlGen.create_includes("ieee", ["std_logic_1164.all"])
			self.hdlGen.wr_nl()

		wrk_pkgs = [self.memMap.name.lower() + "_pkg.all", "cmn_reg_map_pkg.all"]
		self.hdlGen.create_includes("ctu_can_fd_rtl", wrk_pkgs)

		# Create entity definition
		entity = self.create_reg_block_template(block)

		# Create architecture of Register Block
		architecture = LanDeclaration("rtl", entity.name)
		architecture.intType = "architecture"
		intSignals = {}
		architecture.ports = intSignals

		# Write declaration of internal architecture signals
		self.create_internal_decls(block, intSignals)

		# Start architecture
		self.hdlGen.create_comp_instance(architecture)

		# Write driver for write enable
		self.create_write_en_assign()

		# Create instance of write address generator
		self.create_addr_decoder(block)

		# Create instance of registers
		self.create_write_reg_instances(block)

		# Create driver for enable signal for read data multiplexor
		#self.create_read_data_mux_ena()

		# Create Data multiplexor for data reads
		self.create_read_data_mux_instance(block)

		# Create Driver for read data signal
		self.create_read_data_mux_in(block)
		self.create_read_data_mask_driver()

		# Create connections of internal write register record to output
		self.create_write_reg_record_driver(block)
		self.hdlGen.wr_line("\n")

		# Create PSL functional coverage entries
		self.create_reg_access_cover_points(block)

		self.hdlGen.wr_line("\n")
		self.hdlGen.commit_append_lines_all()


	def create_output_reg_record(self, block):
		"""
		Create record for writable registers from IP-XACT memory block object
		according to following rules:
			1. Entry for each register field (<reg_name>_<field_name>)
			2. Entry for each register which should have read/write signallization
		If register write should be indicated, additional <reg_name>_write signal
		is added.
		If register read should be indicated, additional <reg_name>_read signal is
		added.
		"""
		outDecls = []
		outName = block.name.lower() + "_out_t"

		# Create the declarations
		for i,reg in enumerate(sorted(block.register, key=lambda a: a.addressOffset)):

			for field in sorted(reg.field, key=lambda a: a.bitOffset):
				if ("write" in reg.access):
					outDecls.append(LanDeclaration(reg.name + "_" + field.name, value=""))
					if field.bitWidth > 1:
						outDecls[-1].type = "std_logic_vector"
					else:
						outDecls[-1].type = "std_logic"
					outDecls[-1].bitWidth = field.bitWidth
					outDecls[-1].specifier = ""

			if (self.is_reg_write_indicate(reg)):
				outDecls.append(LanDeclaration(reg.name + "_update", value=""))
				outDecls[-1].type = "std_logic"
				outDecls[-1].bitWidth = 1
				outDecls[-1].specifier = ""

			if (self.is_reg_read_indicate(reg)):
				outDecls.append(LanDeclaration(reg.name + "_read", value=""))
				outDecls[-1].type = "std_logic"
				outDecls[-1].bitWidth = 1
				outDecls[-1].specifier = ""

		# Format the declaration
		self.hdlGen.format_decls(outDecls, gap=2, alignLeft=True,
					alignRight=False, alignLen=30, wrap=False)

		self.hdlGen.create_structure(outName, outDecls, gap = 2)


	def create_input_reg_record(self, block):
		"""
		Create record for readable registers from IP-XACT memory block object.
		Add record entry for each register field.
		"""
		# Input Declarations record
		inDecls = []
		inName = block.name + "_in_t"

		for i,reg in enumerate(sorted(block.register, key=lambda a: a.addressOffset)):

			# All registers with read, but not read-write, since read-write is register
			# whose value is written and the same value is read back
			if (("read" in reg.access) and (reg.access != "read-write")):

				for field in sorted(reg.field, key=lambda a: a.bitOffset):
					inDecls.append(LanDeclaration(reg.name + "_" + field.name, value=""))
					if field.bitWidth > 1:
						inDecls[-1].type = "std_logic_vector"
					else:
						inDecls[-1].type = "std_logic"
					inDecls[-1].bitWidth = field.bitWidth
					inDecls[-1].specifier = ""

		# Format the declaration
		self.hdlGen.format_decls(inDecls, gap=2, alignLeft=True,
					alignRight=False, alignLen=30, wrap=False)

		self.hdlGen.create_structure(inName, inDecls, gap = 2)


	def create_mem_block_records(self, block):
		"""
		Create records for register module input/outputs. Each writable
		register is present in "write record". Each readable register is
		present in a read record.
		"""
		self.hdlGen.wr_nl()

		self.create_output_reg_record(block)

		self.hdlGen.wr_nl()
		self.hdlGen.wr_nl()

		self.create_input_reg_record(block)

		self.hdlGen.wr_nl()


	def write_reg_map_pkg(self):
		"""
		Create package with declarations of register map input / output
		records.
		"""
		self.hdlGen.wr_nl()

		self.hdlGen.write_comment("Register map package for: " +
				self.memMap.name, gap = 0)
		self.hdlGen.write_gen_note()
		self.hdlGen.wr_nl()

		if (type(self.hdlGen) == VhdlGenerator):
			self.hdlGen.create_includes("ieee", ["std_logic_1164.all"])
			self.hdlGen.wr_nl()

		self.hdlGen.create_package(self.memMap.name.lower() + "_pkg")

		for block in self.memMap.addressBlock:

			# Skip blocks marked as memory
			if (block.usage == "memory"):
				continue

			self.create_mem_block_records(block)

		self.hdlGen.commit_append_line(1)


