#
# \brief  Environment for executing Genode on Microblaze
# \author Norman Feske
# \author Martin Stein
# \date   2010-09-01
#
# For the documentation of the implemented API functions,
# please refer to the comments in 'tool/run'.
#

proc create_boot_directory { } {
	catch {
		exec rm -rf [run_dir]
		exec mkdir -p [run_dir]
	}
}


proc build {targets {build_core 0}} {

	if {[get_cmd_switch --skip-build]} return

	regsub -all {\s\s+} $targets " " targets

	# Save building 'core' until last
	if {$build_core == 0} {
		regsub -all {\mcore\M} $targets "" targets
	}

	puts "building targets: $targets"
	set timeout 10000
	set pid [eval "spawn make $targets"]
	expect { eof { } }
	if {[lindex [wait $pid] end] != 0} {
		puts "Error: Genode build failed"
		exit -4
	}
	puts "genode build completed"
}

proc stripped_copy {binary} {
	exec mkdir -p bin/stripped/
	exec rm -rf bin/stripped/$binary
	exec cp bin/${binary} bin/stripped/${binary}
	catch {exec [cross_dev_prefix]strip bin/stripped/${binary}}
}


#
# Microblaze needs a single boot image, thus this function creates an temporary assembly file that
# includes all images wich are needed by the boot image to be included by it
#
proc build_boot_modules {} {

	global boot_modules
	global boot_modules_s
	set boot_modules_s "[genode_dir]/base-mb/src/core/boot_modules.s"

	exec echo -e \
		"\n/**"\
		"\n * This file was generated by the expect procedure"\
		"\n * 'build_boot_modules' in 'run/env'"\
		"\n */"\
		"\n\n"\
		"\n.global _boot_modules_meta_start" \
		"\n.global _boot_modules_meta_end" \
		"\n\n" \
		"\n.section .data" \
		"\n.string \"GROM\"" \
		"\n.long header_end" \
		"\n.align 4" \
		"\n_boot_modules_meta_start:" > $boot_modules_s

	# Header, pointers part
	set i 1
	foreach module $boot_modules {
		exec echo -e \
			"\n.long mod${i}_name" \
			"\n.long mod${i}_start" \
			"\n.long mod${i}_end - mod${i}_start" >> $boot_modules_s
		incr i
	}

	exec echo -e \
		"\n.align 4"\
		"\n_boot_modules_meta_end:" >> $boot_modules_s

	# Header, names part
	set i 1
	foreach module $boot_modules {
		exec echo -e \
			"\nmod${i}_name:" \
			"\n.string \"${module}\"" \
			"\n.byte 0" >> $boot_modules_s
		incr i
	}

	exec echo -e "header_end:" >> $boot_modules_s

	# Modulecontents
	set i 1
	foreach module $boot_modules {
		exec echo -e ".align 12" >> $boot_modules_s

# Stripped images the boot image depends on are not enabled because 'mb-strip' destroys 
# the file offset alignments and Genode needs a specific minimum file offset alignment
#
#		if { [catch {exec [cross_dev_prefix]readelf -h bin/${module}}] } {
			exec echo -e "mod${i}_start: .incbin \"../bin/${module}\"" >> $boot_modules_s
#		} else {
#			exec echo -e "mod${i}_start: .incbin \"../bin/stripped/${module}\"" >> $boot_modules_s
#		}
		exec echo -e "mod${i}_end:" >> $boot_modules_s
		incr i
	}

	exec echo -e ".align 12" >> $boot_modules_s
}


proc build_boot_image {images} {
	global boot_modules
	global boot_modules_s

	foreach image $images {
		if {$image != "core"} {

# Stripped images the boot image depends on are not enabled because 'mb-strip' destroys 
# the file offset alignments and Genode needs a specific minimum file offset alignment
#
#			if { [catch {exec [cross_dev_prefix]readelf -h bin/${image}}] == 0 } {
#				stripped_copy $image
#			}
			append boot_modules "${image}" " "
		}
	}

	build_boot_modules
	build "core" 1
	stripped_copy "core"
	catch {
		exec ln -sf ../../../bin/stripped/core [run_dir]/image.elf
	}
	exec rm -f $boot_modules_s
}

proc run_genode_until {{wait_for_re forever} {timeout_value 0}} {

	set image [pwd]/[run_dir]/image.elf
	set target [get_cmd_arg --target "qemu"]

	if { $target == "jtag" } {

		# try to run on device via jtag
		spawn make -C [genode_dir]/base-mb/platform/[hardware] upload IMAGE=$image VERBOSE=
		interact

	} elseif { $target == "qemu" } {

		# run on qemu
		global output
		set timeout $timeout_value
		set pid [spawn [qemu] -kernel $image -serial stdio]
		if {$wait_for_re == "forever"} { interact $pid }
		expect {
			-re $wait_for_re { }
			timeout { puts stderr "Error: Test execution timed out"; exit -2 }
		}
		set output $expect_out(buffer)
	} else {

		puts stderr "Error: Target '${target}' is not supported"
		puts stderr "       Supported targets are: 'jtag' and 'qemu'"; exit -3

	}
}


proc install_config {config} {
	global boot_modules
	append boot_modules "config" " "

	set fh [open "bin/config" "WRONLY CREAT TRUNC"]
	puts $fh $config
	close $fh
	exec touch [genode_dir]/base-mb/src/core/boot_modules.s
}


proc qemu { } {
	global _qemu
	set _qemu [get_cmd_arg --qemu "qemu-system-microblaze"]
	return $_qemu
}

proc hardware { } {
	global _hardware

	#
	# Test on all supported platforms
	#

	if { [have_spec {mb_s3a_starter_kit}] } { 
		set _hardware mb_s3a_starter_kit
		return $_hardware
	}
	if { [have_spec {mb_ml507}] } { 
		set _hardware mb_ml507
		return $_hardware
	}
}
