#!/usr/bin/ruby -Ks
#
# vhd2tbtmpl.rb
# v0.0.4
# 20121108
# akinobu nishi
#

require 'kconv'
win_flag = 0
if(win_flag == 1)
	require 'Win32API' # 20120619 add
end

print("input vhdl file ex)test.vhd\n")
vhdl_name	= STDIN.gets.chomp
p((File::dirname(vhdl_name)))
vhdl_name_buf = vhdl_name.sub(File::dirname(vhdl_name),"").sub("\\","") # 20121108 add if linux then "/"?,if windows then "\\"
if(File::dirname(vhdl_name) == ".") # current directory
	out_vhdl_name = "tb_" + vhdl_name # 20121108 del
else # 絶対パス
	out_vhdl_name = File::dirname(vhdl_name) + "\\" + "tb_" + vhdl_name_buf # 20121108 add if linux then "/"?,if windows then "\\"
end
##########
# 初期化
file_out = File.open(out_vhdl_name,"w")
file_out.close
file_entity_out = File.open("entity_out.vhd","w")
file_entity_out.close
##########

generic_flag = 0

def vhdl_name(f_name_ref)
  @f_name_ref = f_name_ref.chomp
end
def comment_check(din)
	if((din2 = din.lstrip) =~ /\A--/)
		data	= nil
		print("a")
	else
		data	= din
	end
	return data
end

def library_use_check(din)
	if(((din_lstrip = din.lstrip.downcase) =~ /\Alibrary/) || ((din_lstrip = din.lstrip.downcase) =~ /\Ause/))
		data = din
		print("c")
	else
		data	= nil
		print("b")
	end
	return data
end

def entity_check(din)
	if((din_lstrip = din.lstrip.downcase) =~ /\Aentity/)
		din2 = din_lstrip.downcase.sub("entity","")
		din3 = din2.sub("is","")
		# data = din3
		data = 1
		print("gggg")
	else
		data	= 0
		print("hhhh")
	end
	return data
end

def generic_check(din)
	# if(din != nil)
		# din.each_byte {|c| sum = sum + c}
	# end

	if((din_lstrip = din.lstrip.downcase) =~ /\Ageneric/)
		din2 = din_lstrip.downcase.sub("generic","")
		din3 = din2.sub("is","")
		# data = din3
		data = 1
		print("gaaa")
	else
		data	= 0
		print("haaa")
	end
	return data
end

def port_check(din)
	# if(din != nil)
		# din.each_byte {|c| sum = sum + c}
	# end

	if((din_lstrip = din.lstrip.downcase) =~ /\Aport/)
		din2 = din_lstrip.downcase.sub("port","")
		din3 = din2.sub("is","")
		# data = din3
		data = 1
		print("g")
	else
		data	= 0
		print("h")
	end
	return data
end

def file_out(name,type,data)
file_out = File.open(name,type)
file_out.write(data)
file_out.close
end

## init
st = 1
st_entity = 1
entity_data = []
cnt = 0
##
in_file = File.open(vhdl_name, "r")
while din = in_file.gets	# 1行ずつデータ読み込み nilまで
	if(check = din.downcase.include?("entity"))
		st = 2
	end
	case st
	when 1
		dout = library_use_check(din)
	when 2
		case st_entity
		when 1
			dout = ""
			file_out("entity_out.vhd","a",din)
			cnt += 1
			if(check = din.downcase.include?("end"))
				st_entity = 2
			end
		when 2
			# if(check = din.include?("generic"))
				# dout = ""
				# st_entity = 3
		# print("i")
			# end
			# if(check = din.include?("port"))
				# dout = ""
				# st_entity = 4
		# print("j")
			# end
		# when 3
			# gen_data = generic_check
			# if(gen_data == "end")
				# st_entity = 4
			# end
		# when 4
			# port_data = port_check
			# if(port_data == "end")
				# st_entity = 5
			# end
		else
		end
	else
	end

	file_out(out_vhdl_name,"a",dout)

end

st = 1
din_buf = []
comment_flag = 0
# data_gen_buf = []
# data_port_buf = []
data_gen_buf = Array.new(100000) # 20120927 change 10 to 100000
data_gen_buf.each_index{ |y|
data_gen_buf[y] = Array.new(3, "") # ""で初期化 
}
data_port_buf = Array.new(100000)  # 20120927 change 10 to 100000
data_port_buf.each_index{ |y|
data_port_buf[y] = Array.new(3, "") # ""で初期化 
}
entity_name = ""
check_str = ""
i = 0
j = 0
in_file = File.open("entity_out.vhd", "r")
while din = in_file.getc	# 1文字ずつデータ読み込み nilまで
	din = din.chr
	din_buf = [din_buf,din]
	din2 = din_buf.to_s
	if(check = din2.include?("--"))
		comment_flag = 1
	else
	end
	if(comment_flag == 1)
		if(din == "\n")
			din_buf = []
			comment_flag = 0
		end
	end

	if(comment_flag == 0)
		case st
		when 1
			check_str = "entity"
			if(check = din2.downcase.include?(check_str))
				st = 2
				din_buf = []
		print(st)
			end
		when 2
			check_str = " "
			if(din == check_str)
				# entity_name = din2.strip
				din_buf = []
				st = 3
		print(st)
			end
		when 3
			check_str = "is"
			if(check = din2.downcase.include?(check_str))
				din2 = din2.downcase # 20121108 add
				din2.sub!(check_str,"")
				entity_name = din2.strip
				st = 4
				din_buf = []
		print(entity_name)
		print(st)
			end
		when 4
			i = 0
			j = 0
			check_str = "generic"
			if((check = generic_check(din2)) == 1)
			# if(check = din2.downcase.include?(check_str))
				st = 5
				din_buf = []
				generic_flag = 1 # 20120916 add
		print(st)
			end
			check_str = "port"
			if((check = port_check(din2)) == 1)
			# if(check = din2.downcase.include?(check_str))
				st = 6
				din_buf = []
		print(st)
			end
		when 5
			check_str = "("
			if(din == check_str)
				data1 = din2.strip
				din_buf = []
				st = 51
		print(st)
			end
		when 51
			check_str = ":"
			if(din == check_str)
				din2.sub!(check_str,"")
				data_gen_buf[i][j] = din2.strip
				j += 1
				din_buf = []
				st = 52
		print(data_gen_buf)
		print(st)
			end
			check_str = ");"
			if(check = din2.downcase.include?(check_str))
				st = 4
				din_buf = []
			end
		when 52
			check_str = ":="
			if(check = din2.downcase.include?(check_str))
				din2.sub!(check_str,"")
				data_gen_buf[i][j] = din2.strip
				j += 1
				din_buf = []
				st = 53
		print(st)
			end
			check_str = "\n"
			if(din == check_str)
				din2.sub!(check_str,"")
				data_gen_buf[i][j] = din2.strip
				j += 1
				din_buf = []
				st = 4
		print(st)
			end
			
		when 53
			check_str = "\n"
			if(din == check_str)
				din2.sub!(check_str,"")
				data_gen_buf[i][j] = din2.strip
				i_gen_buf = i
				j = 0
		print(data_gen_buf)
				din_buf = []
				st = 54
		print(st)
			end
			check_str = ";"
			if(din == check_str)
				din2.sub!(check_str,"")
				data_gen_buf[i][j] = din2.strip
				i += 1
				j = 0
		print(data_gen_buf)
				din_buf = []
				st = 51
		print(st)
			end
		when 54
			i = 0
			j = 0
			check_str = ");"
			if(check = din2.include?(check_str))
				din_buf = []
				st = 4
		print(st)
			end
		when 6
			check_str = "("
			if(din == check_str)
				data1 = din2.strip
				din_buf = []
				st = 61
		print(st)
			end
		when 61
			check_str = ":"
			if(din == check_str)
				din2.sub!(check_str,"")
				data_port_buf[i][j] = din2.strip
				j += 1
				din_buf = []
				st = 62
		print(st)
			end
			check_str = ");"
			if(check = din2.downcase.include?(check_str))
				st = 7
				din_buf = []
			end
		when 62
			check_str = "in out inout"
			if((check = din2.downcase.include?("in")) || (check = din2.downcase.include?("out")) || (check = din2.downcase.include?("inout")))
				data_port_buf[i][j] = din2.strip
				j += 1
				din_buf = []
				st = 63
		print(st)
			end
		when 63
			check_str = "\n"
			if(din == check_str)
				din2.sub!(check_str,"")
				data_port_buf[i][j] = din2.strip
				i_port_buf = i
				j = 0
				print(din2)
				print(data_port_buf)
				din_buf = []
				st = 64
		print(st)
			end
			check_str = ";"
			if(din == check_str)
				din2.sub!(check_str,"")
				data_port_buf[i][j] = din2.strip
				i += 1
				j = 0
				din_buf = []
				st = 61
		print(st)
			end
		when 64
			check_str = ");"
			if(check = din2.include?(check_str))
				din_buf = []
				st = 7
		print(st)
			end
		when 7

		else
		end

	end
end	
print("\n")
	
data = "entity tb_" + entity_name +" is
end tb_" + entity_name + ";
architecture tb_" + entity_name + "_arch of tb_" + entity_name + " is\n\n"

file_out(out_vhdl_name,"a",data)

for i in 0..i_port_buf
	data = "signal " + data_port_buf[i][0] + "		: " + data_port_buf[i][2] + ";\n"
	file_out(out_vhdl_name,"a",data)
end

data = "COMPONENT " + entity_name + "\n"
file_out(out_vhdl_name,"a",data)

if(generic_flag == 1) # 20120916 add
data = "
	generic(
"
file_out(out_vhdl_name,"a",data)

if(data_gen_buf[0][0] != "") # 20120619 add
	for i in 0..i_gen_buf
		if(i == i_gen_buf)
			data = "		" + data_gen_buf[i][0] + "	: " + data_gen_buf[i][1] + " := " + data_gen_buf[i][2] + "
	"
		else
			data = "		" + data_gen_buf[i][0] + "	: " + data_gen_buf[i][1] + " := " + data_gen_buf[i][2] + ";
	"
		end
		file_out(out_vhdl_name,"a",data)
	end
end
data = "		);"
file_out(out_vhdl_name,"a",data)
end

data = "
	PORT (
"
file_out(out_vhdl_name,"a",data)

for i in 0..i_port_buf
	if(i == i_port_buf)
		data = "	" + data_port_buf[i][0] + " 			: " + data_port_buf[i][1] + " " + data_port_buf[i][2] + "\n"
	else
		data = "	" + data_port_buf[i][0] + " 			: " + data_port_buf[i][1] + " " + data_port_buf[i][2] + ";\n"
	end
	file_out(out_vhdl_name,"a",data)
end

data = "	);
END COMPONENT;

BEGIN
"
file_out(out_vhdl_name,"a",data)

data = 	"i1 : " + entity_name + "\n"
file_out(out_vhdl_name,"a",data)

if(generic_flag == 1) # 20120916 add
data = "
	generic map(
"
file_out(out_vhdl_name,"a",data)

if(data_gen_buf[0][0] != "") # 20120619 add
	for i in 0..i_gen_buf
		if(i == i_gen_buf)
			data = "		" + data_gen_buf[i][0] + " => " + data_gen_buf[i][2] + "
	"
		else
			data = "		" + data_gen_buf[i][0] + " => " + data_gen_buf[i][2] + ",
	"
		end
		file_out(out_vhdl_name,"a",data)
	end
end
data = "	)"
file_out(out_vhdl_name,"a",data)

end
data = "
	PORT MAP (
"
file_out(out_vhdl_name,"a",data)

for i in 0..i_port_buf
	if(i == i_port_buf)
		data = "	" + data_port_buf[i][0] + " 			=> " + data_port_buf[i][0] + "\n"
	else
		data = "	" + data_port_buf[i][0] + " 			=> " + data_port_buf[i][0] + ",\n"
	end
	file_out(out_vhdl_name,"a",data)
end
data = "	);

	init1 : process                                               
	begin                                                        
		rst_n <= '0';
		wait for 3000 ns;
		rst_n <= '1';
		wait;
	END process init1;                                           

	init2 : process -- 10MHz = 100us/1cycle
	begin
		 loop
			clk <= '0';
			wait for 50 ns;
			clk <= '1';
			wait for 50 ns;
		end loop;
	end process init2;

END tb_" + entity_name + "_arch;
"
file_out(out_vhdl_name,"a",data)
# 20120619 add
if(win_flag == 1)
	print("テストベンチ作成完了。" + out_vhdl_name + "が出力されました。\n")
	print("終了するには何かキーを押してください。\n")
	kbhit = Win32API.new('msvcrt','_kbhit',[],'l')
	while true
	   if kbhit.call != 0
		  break
	   end
	end
	puts "\nキーが押されました"
else
	print("testbench template was genarated." + out_vhdl_name + ".\n")

end

