[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [microblaze-uclinux] Petalogix BSP with XPS 9.2



Hi Tom, Tobi,

Ipaye, Tobi wrote:
I have exactly the same problem, it looks like a bug in the way TCL
handles integers. I'm still searching for answers.
Do you have any idea when the next release of the BSP tools will be and
if it will definitely have MPMC support?

You can try the attached MLD and TCL files - just drop them into the petalinux/hardware/edk_user_repository/PetaLogix/bsp/petalinux_v1_00_b/data directory

These are experimental, and have had very little testing. Feedback is welcome.

Regards,

John
#---------------------------------------------------------------------------
#
#   File:       petalinux_v2_1_0.mld
#   Created:    
#   Creator:    
#
#       ===================================================================
#       Copyright C - 2004-2006 All rights reserved. PetaLogix.
#
#       No part of this program may be reproduced or adapted in any form
#       or by any means, electronic or mechanical, without permission from 
#       PetaLogix. This program is confidential and may not be disclosed, 
#       decompiled or reverse engineered without permission in writing from 
#       PetaLogix.
#       ===================================================================
#
#     PetaLogix auto-config BSP Generation tool
#

OPTION psf_version = 2.1;

BEGIN OS petalinux

OPTION DRC = petalinux_drc;
OPTION SUPPORTED_PERIPHERALS = (microblaze ppc405 ppc405_virtex4);
OPTION DESC = "Generate BSP for PetaLogix / PetaLinux kernel 2.4";

PARAMETER name = TARGET_DIR, desc = "Destination directory for PetaLinux BSP (auto-config.in)", type = string;

PARAMETER name = stdout, desc = "stdout peripheral for bootloader", type = peripheral_instance, requires_interface=stdout, default = none;
PARAMETER name = stdin, desc = "stdin peripheral for bootloader", type = peripheral_instance, requires_interface=stdin, default = none;

PARAMETER name = main_memory, desc ="Name of Main Memory used with PetaLinux", type = peripheral_instance, range=(opb_ddr,opb_emc,plb_ddr,plb_emc,opb_sdram,plb_sdram,mch_opb_sdram,mch_opb_ddr, mch_opb_ddr2, mch_opb_emc, plb_ddr2, mpmc), default = none;
PARAMETER name = main_memory_bank, desc="Bank Nr. within memory controller of main memory", type = integer, default = -1;
PARAMETER name = main_memory_start, desc="Manual override of main memory start address",type = integer, default = -1;
PARAMETER name = main_memory_size, desc="Manual override of main memory size", type = integer, default = 0;
PARAMETER name = main_memory_offset, desc="Manual override of main memory start offset", type = integer, default = 0;

PARAMETER name = flash_memory, desc ="Name of Flash Memory Controller used with PetaLinux", type = peripheral_instance, range=(opb_emc,plb_emc,mch_opb_emc, xps_mch_emc,none), default = none;
PARAMETER name = flash_memory_bank, desc="Bank Nr. within memory controller of flash memory", type = integer, default = -1;
PARAMETER name = flash_memory_start, desc="Manual override of flash memory startaddress", type=integer, default=-1;
PARAMETER name = flash_memory_size, desc="Manual override of flash memory size", type = integer, default = 0;
PARAMETER name = flash_memory_offset, desc="Manual override of flash memory start offset", type = integer, default = 0;

PARAMETER name = lmb_memory, desc = "Name of LMB Memory used with PetaLinux", type = peripheral_instance, range=(lmb_bram_if_cntlr,opb_bram_if_cntlr,none), default = none;

PARAMETER name = periph_type_overrides, desc = "List of peripheral type overrides", type = string, default = "";

BEGIN CATEGORY microblaze_exceptions
        PARAM name = microblaze_exceptions, type = bool, default = false, desc = "Setting ignored", permit = none, dep = (special = microblaze);

BEGIN ARRAY microblaze_exception_vectors
        PROPERTY desc = "Unused. Exception handling managed by PetaLinux kernel";
        PROPERTY size = 1;
        PROPERTY default = ((XEXC_NONE, default, 1));
        PARAM name = exception, type = enum, values = ("Unused" = XEXC_NONE), desc = "Unused", permit=none;
        PARAM name = handler, type = string, desc = "Unused";
        PARAM name = callback, desc = "Unused";

END ARRAY
END CATEGORY


END OS
#---------------------------------------------------------------------------
#
#   File:       petalinux_v2_1_0.tcl
#   Created:    
#   Creator:    
#
#       ===================================================================
#       Copyright C - 2004-2006 All rights reserved. PetaLogix.
#
#       No part of this program may be reproduced or adapted in any form
#             or by any means, electronic or mechanical, without
#       permission from PetaLogix. This program is confidential and
#           may not be disclosed, decompiled or reverse engineered
#           without permission in writing from PetaLogix.
#       ===================================================================
#
#     PetaLogix' Embedded Linux auto-config BSP Generation tool
#
# Known limitations:



# Globals
# config_file and hdr_file hold file handles for the
# auto-config.in and auto-config.h files respectively.
# kconfig_file is for the 2.6 kernel Kconfig settings
# they are global to save passing them around to all functions
set config_file {}
set kconfig_file {}
set hdr_file {}

# Initialise the driver list as an empty list
set drvlist [list]

# periph_count is a map that tracks the number of instances of each
# peripheral type
array set periph_count {}

# override_array stores any periph_type overrides specified in the MSS
array set override_array {}

# Create a namespace that incorporates the standalone BSP functionality
proc create_standalone_namespace {} {
    namespace eval standalone_bsp {
        global env
        set edk_path $env(XILINX_EDK)
        source ${edk_path}/sw/lib/bsp/standalone_v1_00_a/data/standalone_v2_1_0.tcl
    }
} 

proc petalinux_drc {os_handle} {
    puts "\#--------------------------------------"
    puts "\# PetaLogix / PetaLinux BSP DRC...!"
    puts "\#--------------------------------------"
}

proc process_core_override_list {os_handle} {

	global override_array

	# Make sure override_array is empty on entry to this function
	array unset override_array
	array set override_array {}
	global override_array
	
	# Was a core_overrides parameter specified in the OS section?
	set overrides [xget_sw_parameter_value $os_handle "periph_type_overrides"]

	if {[string match $overrides ""]} {
		return
	}

	# Now parse this string, saving results into a global array
	foreach override $overrides {
		set instance [string toupper [lindex $override 0]]
		set new_type [string toupper [lindex $override 1]]
		set override_array($instance) $new_type
	}
}

proc generate {os_handle} {
    global config_file hdr_file kconfig_file
    global edk_path
    global env

    set edk_path $env(XILINX_EDK)
    create_standalone_namespace

    variable drvlist
    puts "\#--------------------------------------"
    puts "\# PetaLinux BSP generate..."
    puts "\#--------------------------------------"    
    
    # open the config file
    set config_file_name "auto-config.in"
    set config_file [open $config_file_name w]
    
    # open the kconfig file
    set kconfig_file_name "Kconfig.auto"
    set kconfig_file [open $kconfig_file_name w]
    
    # open our local auto-config.h file (used by first stage bootloader)
    set hdr_file_name "auto-config.h"
    set hdr_file [xopen_include_file $hdr_file_name]
    
    # print the header
    #set desc "PetaLinux Configuration File"
    generate_header 
    generate_generic ""

    
    # get software processor handle
    # This call returns the current processor handle for which libgen
    # algorithm is being run
    set proc_handle [xget_libgen_proc_handle]

    # output memory configuration data
    do_memory_setup $os_handle "MAIN_MEMORY" XILINX_ERAM
    do_memory_setup $os_handle "FLASH_MEMORY" XILINX_FLASH
    do_memory_setup $os_handle "LMB_MEMORY" XILINX_LMB

    process_core_override_list $os_handle

    # print processor related params
    generate_processor_params $proc_handle
    
    # Get list of drivers of peripherals connected to the processor
    set drvlist [xget_handle $proc_handle "DRIVER" "*"]

    # print the device params
    generate_device_params

    # Point into Xilinx EDK to get standalone BSP files, so we don't
    # need to duplicate them here

    set orig_mbsrcdir "${edk_path}/sw/lib/bsp/standalone_v1_00_a/src/microblaze"
    set orig_ppcsrcdir "${edk_path}/sw/lib/bsp/standalone_v1_00_a/src/ppc405"
    set orig_profilesrcdir "${edk_path}/sw/lib/bsp/standalone_v1_00_a/src/profile"
    set mbsrcdir "./src/microblaze"
    set ppcsrcdir "./src/ppc405"
    set profilesrcdir "./src/profile"

    file mkdir "./src"
    file copy ${orig_mbsrcdir} $mbsrcdir
    file copy ${orig_ppcsrcdir} $ppcsrcdir
    file copy ${orig_profilesrcdir} $profilesrcdir

    puts "Calling standalone::generate"
    standalone_bsp::generate $os_handle

    # handle the stdout and stdin params, for the bootloader
    xhandle_stdout $os_handle
    xhandle_stdin $os_handle
    
    # close the file...
    close $config_file
    close $kconfig_file
    close $hdr_file
}

##################################################
# procedure post_generate
# This copies the auto-config.in file into the kernel tree
# if required
##################################################

proc post_generate {lib_handle} {
    set config_file_name "auto-config.in"
    set kconfig_file_name "Kconfig.auto"

    set value [xget_value $lib_handle "PARAMETER" TARGET_DIR]

    if {$value != ""} {
        if {[file isdirectory $value] == 0} {
            exec bash -c "mkdir -p $value"
        }
        exec bash -c "cp $config_file_name $value"
#       exec bash -c "cp $kconfig_file_name $value"
    }
    standalone_bsp::post_generate ${lib_handle}
}

proc do_manual_memory_setup {os_handle param_prefix config_prefix} {
    global config_file kconfig_file hdr_file
	set proc_handle [xget_libgen_proc_handle]

	# Get manually specified start address and size
	set mem_start [xget_sw_parameter_value $os_handle "${param_prefix}_START"]
	set mem_size [xget_sw_parameter_value $os_handle "${param_prefix}_SIZE"]

	# Did we get valid start and size?
	if {$mem_start==-1 || [string match $mem_start ""] || $mem_size==0 || [string match $mem_size ""]} {
		# Format warning/error msg
		set msg "No ${param_prefix} peripheral or START/SIZE parameters specified"
		# For main memory, this is fatal
		if { [string match $param_prefix "MAIN_MEMORY"] } {
			error "ERROR :: ${msg}"
		} else {
			puts "WARNING :: ${msg}"
		}
		return
	} 

	# Format start_addr and size as hex strings
	set mem_start [format "0x%08x" $mem_start]
	set mem_size [format "0x%08x" $mem_size]
	
	# Generate config file entries
	generate_comment "$param_prefix Settings"
	generate_hex_param "${config_prefix}_START" "$mem_start" "Start address of ${config_prefix}"
	generate_hex_param "${config_prefix}_SIZE" "$mem_size" "Size of ${config_prefix}"
	generate_generic ""
}

proc do_memory_setup {os_handle param_prefix config_prefix} {
	global config_file kconfig_file hdr_file
	# print system memory
	set proc_handle [xget_libgen_proc_handle]
	
	# Get memory peripheral instance
	set mem [xget_sw_parameter_value $os_handle $param_prefix]

	# Get any overridden start address and size
	set mem_start_override [xget_sw_parameter_value $os_handle "${param_prefix}_START"]
	set mem_size_override [xget_sw_parameter_value $os_handle "${param_prefix}_SIZE"]
	# Did MSS file specify a memory peripheral instance?
	if {[string match "" $mem] || [string match "none" $mem]} {
		# if not, see if START/SIZE params were given
		do_manual_memory_setup $os_handle $param_prefix $config_prefix
		return
	}

	set mem_bank [xget_sw_parameter_value $os_handle "${param_prefix}_BANK"]
	set mem_handle [xget_sw_ipinst_handle_from_processor $proc_handle $mem]

	# Was it a valid instance?
	if {[string match $mem_handle ""]} {
		error "ERROR :: $param_prefix peripheral $mem does not exist"
	}

	# What memory controller is this?
	set controller_type [xget_hw_value $mem_handle];

	# Check for MPMC vs banked vs direct memory core
	if {[string match $controller_type "mpmc"]} {
		set base_param_name "C_MPMC_BASEADDR"
		set high_param_name "C_MPMC_HIGHADDR"
	} elseif {$mem_bank == -1 || [string match $mem_bank ""]} {
		set base_param_name "C_BASEADDR" 
		set high_param_name "C_HIGHADDR"
		set width_param_name "C_MEM_WIDTH"
		set dwidth_match_param_name "C_INCLUDE_DATAWIDTH_MATCHING" 
	} else {
		set base_param_name [format "C_MEM%i_BASEADDR" $mem_bank]
		set high_param_name [format "C_MEM%i_HIGHADDR" $mem_bank]
		set width_param_name [format "C_MEM%i_WIDTH" $mem_bank]
		set dwidth_matching_param_name [format "C_INCLUDE_DATAWIDTH_MATCHING_%i" $mem_bank]
	}

	# Process memory core parameters
	set mem_start [xget_sw_parameter_value $mem_handle $base_param_name]
	set mem_end [xget_sw_parameter_value $mem_handle $high_param_name]

	# remove any embedded underscore characters
	set mem_start [string map {"_" ""} $mem_start]
	set mem_end [string map {"_" ""} $mem_end]

	# Manual override of memory region start
	if {$mem_start_override==-1 || [string match $mem_start_override ""]} {
	} else {
		set mem_start $mem_start_override
	}

	# Manual override of memory region size
	if {$mem_size_override==0 || [string match $mem_size_override ""]} {
		set mem_size [expr $mem_end - $mem_start + 1]
	} else {
		set mem_size $mem_size_override
	}

	# Manual override of memory region offset relative to start
	set mem_offset_override [xget_sw_parameter_value $os_handle "${param_prefix}_OFFSET"]
	if {$mem_offset_override==0 || [string match $mem_offset_override ""]} {
        } else {
		set mem_start [expr $mem_start + $mem_offset_override]
	}

	# Format start_addr and size as hex strings
	set mem_start [format "0x%08x" $mem_start]
	set mem_size [format "0x%08x" $mem_size]
	
	# Generate config file entries
	generate_comment "${param_prefix} Settings"
	generate_hex_param "${config_prefix}_START" "$mem_start" "Start address of ${config_prefix}"
	generate_hex_param "${config_prefix}_SIZE" "$mem_size" "Size of ${config_prefix}"
	# Handle flash width and datawidth matching
	if { [string match ${param_prefix} "FLASH_MEMORY"] } {
		set mem_width [xget_sw_parameter_value $mem_handle $width_param_name]
		set dwidth_matching [xget_sw_parameter_value $mem_handle $dwidth_matching_param_name]
		generate_int_param ${config_prefix}_WIDTH $mem_width "Bus width of ${config_prefix}"
		generate_int_param ${config_prefix}_DATAWIDTH_MATCHING $dwidth_matching "Is datawidth matching enabled on this flash memory?"
	}

	generate_generic ""
} 

proc generate_processor_params {proc_handle} {
    global config_file kconfig_file
    global hdr_file
    
    # print system clock
    set sys_clock [xget_sw_parameter_value $proc_handle "CORE_CLOCK_FREQ_HZ"]
    generate_comment "System Clock Frequency"
    generate_int_param XILINX_CPU_CLOCK_FREQ $sys_clock "System Clock Frequency (Hz)"
    generate_generic ""
    
    # print microblaze params
    set hwproc_handle [xget_handle $proc_handle "IPINST"]
    set args [xget_hw_parameter_handle $hwproc_handle "*"]

    set proctype [xget_value $hwproc_handle "OPTION" "IPNAME"]
    switch $proctype {
        "microblaze" {
            set proc_string "MICROBLAZE0"
        }
        "ppc405" - 
        "ppc405_virtex4" {
            set proc_string "PPC405_0"
        }
        default {
            set proc_string "UNKNOWN"
            puts "unsupported processor type $proctype\n"
        }
    }

    generate_params $proc_string $args    
    generate_generic "" 
}

proc generate_device_params {} {
    
	variable drvlist
	global periph_count
	global config_file kconfig_file hdr_file

	# Make sure periph_counts is empty on entry to this function
	array unset periph_count
	array set periph_count {}
	global periph_count

	foreach drv $drvlist {
		generate_drv_param $drv
	}

	# Output peripheral counts
	generate_comment "Peripheral counts"

	foreach p [array names periph_count] {
		set format_str "XILINX_%s_NUM_INSTANCES"
		generate_int_param [format $format_str $p] $periph_count($p) "Number of ${p} instances"
	}
	generate_generic ""
}

# Returns list in form of { {irq_num portname} {irq_num portname} ...}
proc get_periph_irq_list {periph} {
	set irq_list {}

	# Get any output interrupt ports of this core type
	set intr_ports [xget_port_by_subtype $periph "SIGIS" "INTERRUPT" "DIR" "O"]
	# Any work to do?
	if {[llength $intr_ports] == 0} {
		return
	}

	set num_intr_ports [llength $intr_ports];

	# Get handle to actual MHS instance of this core 
	set mhs_handle [xget_hw_parent_handle $periph]

	# Loop over each interrupt-generating port
	foreach port $intr_ports {
		# What signal (wire) is attached?
		set signal [xget_value $port "VALUE"]
		if {[llength $signal] == 0} {
			continue
		}
		# Get the name of the interrupt port 
		set intr_port_name [string toupper [xget_value $port "NAME"]]

		# Our interrupt output is the source - what about the sink?
		set sink_ports [xget_hw_connected_ports_handle $mhs_handle $signal "sink"]

		# Make sure there is at least one sink port
		if {[string match "" $sink_ports]} {
			puts [format "WARNING: Interrupt signal %s on port %s has no sink" $signal $intr_port_name]
			continue;
		} 

		# Which of these are interrupt controllers?
		set intc_sink_periphs ""
		set intc_sink_ports ""
		set sink_idx 0
		foreach sink_port $sink_ports {
			# Get parent periphs of sink port for IRQ signal
			set sink_periph [xget_hw_parent_handle $sink_port]
			set handletype [xget_value $sink_periph "handletype"]
			# Only get instance type for IPINSTances
			if {![string match -nocase IPINST $handletype]} {
				incr sink_idx;
				continue;
			}

			set sink_periph_name [xget_value $sink_periph "VALUE"]
	
			if {[string match -nocase *_intc $sink_periph_name]} {
				lappend intc_sink_periphs $sink_periph
				lappend intc_sink_ports [lindex $sink_ports $sink_idx]
			}
			incr sink_idx
		}

		# Does the signal drive an interrupt controller?
		if {[llength $intc_sink_periphs] ==0} {
			continue
		}

		# Does it drive more than one controller?
		# Or one controller, more than once maybe?
		if {[llength $intc_sink_periphs] != 1} {
			puts [format "ERROR: Interupt signal %s on port %s connects to multiple interrupt controllers:" $signal $intr_port_name]
			puts $intc_sink_periphs
			continue
		}

		# We've isolated a single sink port on an interrupt controller
		# Enumerate all incoming signals on this sink port 
		set signals [split [xget_value $intc_sink_ports "VALUE"] "&"]

		# What numerical position is our signal in this list?
		set i 1
		foreach s $signals {
			set s [string trim $s]
			if {[string compare -nocase $s $signal] == 0} {
				break
			} 
			incr i
		}

		# Workout the IRQ num
		set posn [expr [llength $signals] - $i]

		lappend irq_list [list $intr_port_name $posn]
	}
	return $irq_list 
}
proc generate_drv_param {drv_handle} {
	global config_file kconfig_file hdr_file
    
	set periphs [xget_sw_iplist_for_driver $drv_handle]
	set device_id -1
	set prev_periph_name ""
	
	# global array to keep count of each peripheral type
	global periph_count

	# Global array tracking periph-type overrides
	global override_array

	foreach periph $periphs {
		set args [xget_hw_parameter_handle $periph "*"]
		set periph_name [string toupper [xget_value $periph "VALUE"]]

		# Handle periph type override (e.g. for EMCs used as generic
		# interface adapters
		
		# Get instance name for current peripheral
		set inst_handle [xget_hw_parameter_handle $periph "INSTANCE"]
		set instance_name [string toupper [xget_value $inst_handle]]
		# Has this instance been overridden?
		if {![string match [array names override_array $instance_name] "" ]} {
			set periph_name $override_array($instance_name)
		}

		# strip any opb_ plb_ or dcr_ prefixes from periph name
		regsub -nocase ^OPB_ $periph_name "" periph_name
		regsub -nocase ^PLB_ $periph_name "" periph_name
		regsub -nocase ^DCR_ $periph_name "" periph_name
		regsub -nocase ^XPS_ $periph_name "" periph_name

		# initialize / update count for this peripheral type
		if {![string compare -nocase "" [array names periph_count $periph_name]]} {
			set periph_count($periph_name) 1
		} else {
			incr periph_count($periph_name)
		}
	
		set device_id [expr $periph_count($periph_name)-1];

		# Output standard core params
		set periph_string [format "%s_%s" $periph_name $device_id]
		generate_params $periph_string $args

		# Special handling for MDM core, but not sure why
		#if {[string compare -nocase $periph_name "opb_mdm"] != 0} {
		#	incr device_id
		#} 

		# Interrupt controller connections
		# Don't process interrupt controller itself
		if {![string match -nocase *_intc $periph_name]} {
			set irq_list [get_periph_irq_list $periph]

			# For periphs with a single interrupt output, it's just called "IRQ"
			# However periphs with multiple interrupt outputs, we name the ports explicitly
			if {[llength $irq_list] == 1} {
				set irq_name [format "XILINX_%s_IRQ" $periph_string]
				set irq_num [lindex [lindex $irq_list 0] 1]
				generate_int_param $irq_name $irq_num "IRQ number of ${periph_string}"
			} else {
				foreach irq_data $irq_list {
					set irq_name [format "XILINX_%s_%s_IRQ" $periph_string [lindex $irq_data 0]]
					set irq_num [lindex $irq_data 1]
					generate_int_param $irq_name $irq_num "IRQ number of ${periph_string} IRQ output [lindex $irq_data 0]"
				}
			}
		}

		generate_generic ""
	}

}

# Convert EDK param of type std_logic_vector into a C-style hex val
proc stdlogicvec_to_hex {param_value} {
	# remove any internal underscore characters, 
	# these are permitted in VHDL/EDK, but not C
	set param_value [string map {_ ""} $param_value]
	
	# Check to see if value starts with 0b or 0x
	if {[string match -nocase 0b* $param_value]} {
		set param_value [xconvert_binary_to_hex $param_value]
	} elseif {[string match -nocase 0x* $param_value]} {
		set param_value [format "0x%08X" $param_value]
	} else {
		# assume malformed binary value, put 0b at the front
		set param_value [xconvert_binary_to_hex 0b$param_value]
	}
	return $param_value;
}

# Create an auto-config paramater name for the parameter who's handle
# is given by h_param
proc get_param_name_string {periph_string h_param} {
	# get the name of the parameter, and format
	set param_name [string toupper [xget_value $h_param "NAME"]]

	# trim leading "C_" 
	regsub -nocase ^C_ $param_name "" param_name

	# morph into config.in naming format
	set param_name [format "XILINX_%s_%s" $periph_string $param_name]
	return $param_name
}


# Create an auto-config parameter value string, for the parameter who's
# handle is given by h_param
proc get_param_value_string {h_param} {
	set param_value [xget_value $h_param "VALUE"]

	# format according to datatype
	set dt [string toupper [xget_hw_subproperty_value $h_param "DT"]]

	switch -regexp $dt {
		INTEGER {
			# Strip out any underscores in the value - MHS
			# syntax permits them, yuck!
			set param_value [string map {_ ""} $param_value]
		}
		STD_LOGIC_VECTOR* {
			# Convert stdlogicvector string to hexval
			set param_value [stdlogicvec_to_hex $param_value];
		}
		STD_LOGIC {
			# No manipulation of param_value required
		}
		STRING {
			# No manipulation of param_value required
		}
		default {
			# No manipulation of param_value required
		}
	}
	return $param_value
}



# Generate a config.in string for a parameter value
proc gen_config_string {periph_string param} {
	set config_string ""

	# get the name of the parameter, and format
	set param_name [string toupper [xget_value $param "NAME"]]

	# trim leading "C_" from param name
	regsub -nocase ^C_ $param_name "" param_name
	#set param_name [string map -nocase {C_ ""} $param_name]

	# morph into config.in naming format
	set param_name [format "XILINX_%s_%s" $periph_string $param_name]

	# Now deal with the value
	set param_value [xget_value $param "VALUE"]

	# format according to datatype
	set dt [string toupper [xget_hw_subproperty_value $param "DT"]]

	switch -regexp $dt {
		INTEGER {
			set param_value [string map {_ ""} $param_value]
			set config_string "define_int $param_name $param_value"
		}
		STD_LOGIC_VECTOR* {
			set config_string "define_hex $param_name [stdlogicvec_to_hex $param_value]"
		}
		STD_LOGIC {
			set config_string "define_int $param_name $param_value"
		}
		STRING {
			set config_string "define_string $param_name $param_value"
		}
		default {
			set config_string "define_string $param_name $param_value"
		}
	}

	return $config_string;
}

# Generate output describing the peripheral names 'periph_string', for
# each of the parameter handles contained in 'h_params'
proc generate_params {periph_string h_params} {
	global config_file kconfig_file hdr_file
    
	generate_comment "Definitions for $periph_string"

	# Process each parameter
	foreach h_param $h_params {
		set param_name [get_param_name_string $periph_string $h_param];
		set param_value [get_param_value_string $h_param];

		# Don't output empty params or values
		if {[string match "" $param_name] || 
		    [string match "" $param_value] } {
			continue;
		}
		
		# Get the datatype of the parameter
		set dt [string toupper [xget_hw_subproperty_value $h_param "DT"]]
		# Get a description of the parameter
		set descr [xget_hw_subproperty_value $h_param "DESC"]
		set name [xget_value $h_param "NAME"]
		set values [xget_hw_subproperty_value $h_param "VALUES"]
		set range [xget_hw_subproperty_value $h_param "RANGE"]
		# Some standard descriptions
		if {[string match "" $descr]} {
			switch $name {
			C_FAMILY {
				set descr "Targetted FPGA family"
			}
			INSTANCE {
				set descr "Core Instance Name"
			}
			HW_VER {
				set descr "Core version number"
			}
			C_BASEADDR {
				set descr "Base address"
			}
			C_HIGHADDR {
				set descr "High address"
			}
			default {
				# Just use the param name as the description
				set descr [regsub -nocase ^C_ $name ""]
			}
			}

			# Append details of possible ranges/values, if known
			if {![string match $range ""]} {
				set descr "${descr} range ${range}"
			}
			if {![string match $values ""]} {
				set descr "${descr} values ${values}"
			}
		}

		# Generate output according to datatype
		switch -regexp $dt {
			INTEGER {
				generate_int_param $param_name $param_value $descr;
			}
			STD_LOGIC_VECTOR* {
				generate_hex_param $param_name $param_value $descr;
			}
			STD_LOGIC {
				generate_int_param $param_name $param_value $descr;
			}
			STRING {
				generate_string_param $param_name $param_value $descr;
			}
			default {
				generate_string_param $param_name $param_value $descr;
			}
		}
	}
}

proc generate_header {} {
    global config_file kconfig_file
    global hdr_file

    puts $config_file "\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\##\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#"
    puts $config_file "\# "
    puts $config_file "\# CAUTION: This file is automatically generated by libgen."
    puts $config_file "\# EDK Version: [xget_swverandbld] "
    puts $config_file "\# Description: PetaLinux Configuration File - Kernel Version 2.4.x"
    puts $config_file "\# "
    puts $config_file "\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\##\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#"
    puts $config_file ""

    puts $kconfig_file "\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\##\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#"
    puts $kconfig_file "\# "
    puts $kconfig_file "\# CAUTION: This file is automatically generated by libgen."
    puts $kconfig_file "\# EDK Version: [xget_swverandbld] "
    puts $kconfig_file "\# Description: PetaLinux Configuration File - Kernel Version 2.6.x"
    puts $kconfig_file "\# "
    puts $kconfig_file "\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\##\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#"
    puts $kconfig_file ""

    puts $hdr_file "/*"
    puts $hdr_file " *"
    puts $hdr_file " * auto-config.h - automatically generated, do not edit"
    puts $hdr_file " *"
    puts $hdr_file " * EDK Version: [xget_swverandbld] "
    puts $hdr_file " */"
    puts $hdr_file ""
}

# Generate a comment into config.in and C header format
proc generate_comment {comment_string} {
    global config_file kconfig_file hdr_file 
    puts $config_file "\# $comment_string"
    puts $kconfig_file "\# $comment_string"
    puts $kconfig_file "comment \"${comment_string}\""
    puts $kconfig_file "      depends on ALLOW_EDIT_AUTO"
    puts $kconfig_file ""
    puts $hdr_file "/* $comment_string */"
}

# Generate a hex-typed parameter into config.in and C header format
proc generate_hex_param {param_name param_value descr} {
    global config_file kconfig_file hdr_file 

    puts $kconfig_file "config ${param_name}"
    puts $kconfig_file "       hex \"${descr}\" if ALLOW_EDIT_AUTO"
    puts $kconfig_file "       default ${param_value}"
    puts $kconfig_file ""

    puts $config_file "define_hex CONFIG_${param_name} ${param_value}"

    puts $hdr_file    "\#define CONFIG_${param_name} (${param_value})"
}

# Generate an integer-typed parameter into config.in and C header format
proc generate_int_param {param_name param_value descr} {
    global config_file hdr_file kconfig_file

    puts $kconfig_file "config ${param_name}"
    puts $kconfig_file "       int \"${descr}\" if ALLOW_EDIT_AUTO"
    puts $kconfig_file "       default ${param_value}"
    puts $kconfig_file ""

    puts $config_file "define_int CONFIG_${param_name} ${param_value}"
    puts $hdr_file    "\#define CONFIG_${param_name} (${param_value})"
}

# Generate a string-typed parameter into config.in and C header format
proc generate_string_param {param_name param_value descr} {
    global config_file hdr_file kconfig_file

    # Strip out any quotes in the string value - we'll add our own
    regsub -nocase \" $param_value "" param_value 

    puts $kconfig_file "config ${param_name}"
    puts $kconfig_file "       string \"${descr}\" if ALLOW_EDIT_AUTO"
    puts $kconfig_file "       default \"${param_value}\""
    puts $kconfig_file ""

    puts $config_file "define_string CONFIG_${param_name} \"${param_value}\""
    puts $hdr_file    "\#define CONFIG_${param_name} \"${param_value}\""
}

# Print identical strings to both auto-config.in and auto-config.h
# No formatting is done, so use with caution
proc generate_generic {text_string} {
    global config_file hdr_file kconfig_file

    puts $kconfig_file "${text_string}"
    puts $config_file "${text_string}"
    puts $hdr_file "${text_string}"
}