ruby QA使用Calibre DRC和SmartFill运行脚本
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ruby QA使用Calibre DRC和SmartFill运行脚本相关的知识,希望对你有一定的参考价值。
#!/usr/local/bin/ruby
#
# QA verification script in Ruby
# Based on C-Shell version by JJ
# By Kala Kuo
#
# 2016.4.7 Init.
# 2016.4.8 Add folder selection, drc_pre cache.
#
# ================== TODO =======================
# o | a. Make selection for DWA/IWA/handoff
# o | b. Make drc_pre as central control version.
# o | c. Requirement (File/Folder) pre-check
# o | d. OASIS version integration
# | e. Print/Read specified debug flag
# | f. Read-in list of GDS/OASIS names as argument
#
require 'logger'
DEBUG_RUN = false
# Ref: http://stackoverflow.com/questions/6407141/how-can-i-have-ruby-logger-log-output-to-stdout-as-well-as-file
class MultiDelegator
def initialize(*targets)
@targets = targets
end
def self.delegate(*methods)
methods.each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
self
end
class <<self
alias to new
end
end
# ===================================================================================================== #
# ========================================== Functions ================================================ #
# ===================================================================================================== #
def Folder_Check(deck_dir, script_dir, db_dir)
until File.exist?(deck_dir)
puts "### Deck folder [#{deck_dir}] is NOT existed."
puts "### Specify the path of Deck folder : "
deck_dir = gets.chomp
end
until File.exist?(script_dir)
puts "### Script folder [#{script_dir}] is NOT existed."
puts "### Specify the path of Script folder : "
script_dir = gets.chomp
end
until File.exist?(db_dir)
puts "### Testcase folder [#{db_dir}] is NOT existed."
puts "### Specify the path of Testcase folder : "
db_dir = gets.chomp
end
end
# Use for Execution Order
def Get_FILE_LIST()
return [
"test.gds",
"test.oas",
]
end
def Get_TopCell(file)
topcell = %x[calibredrv -a puts [layout peek #{file} -topcell]].chomp
topcell = topcell.split("\n")[-1] if topcell.include?("\n")
return topcell
end
def Get_Format(file)
format = %x[calibredrv -a puts [layout peek #{file} -format]].chomp
format = format.split("\n")[-1] if format.include?("\n")
return format
end
def Get_RunTime(file)
time = %x[grep -e "--- TOTAL .* REAL TIME = " #{file}].chomp
return time.include?(" ") ? time.split(' ')[-1] : ""
end
def Make_Sure_Folder_Exist(*dir)
dir.each do |f|
%x[mkdir #{f}] if !File.exist?(f)
end
end
def Cleanup(folder, *files)
files.each do |f|
%x[rm #{folder}/#{f}] if File.exist?("#{folder}/#{f}")
end
end
def Get_Deck(input_file, input_deck, tmp_deck_name)
# input_deck should accept GDSII format input
# If input_file is OASIS format, generate and return OASIS version deck
if Get_Format(input_file).chomp.include?("OAS")
%x[sed -e 's/LAYOUT SYSTEM GDSII/LAYOUT SYSTEM OASIS/' #{input_deck} > #{tmp_deck_name}]
return tmp_deck_name
end
return input_deck
end
def Get_Merge_Script(filename)
if !File.exist?(filename)
filename = "_merge_newtop.abst"
File.open(filename, "w") do |f|
f.puts "set orgds [lindex $argv 0]"
f.puts "set dmgds [lindex $argv 1]"
f.puts "set opfile [lindex $argv 2]"
f.puts "layout filemerge -in $orgds -in $dmgds -out $opfile -createtop NEWTOP"
end
end
return filename
end
# ===================================================================================================== #
# ========================================== End of Func ============================================== #
# ===================================================================================================== #
class Conf
attr_accessor :mgc_home, :deck_dir, :script_dir, :drc_pre_dir, :working_dir,
:db_dir, :out_gds, :out_sum, :drc_out,
:run_id, :run_dir, :report_file,
:fill_deck, :drc_deck, :run_drc
def initialize
# ========================================== CALIBRE SETTING ========================================== #
wa = Get_Calibre_Folder()
@mgc_home = wa.include?("_cal_") ? wa : "#{wa}/ic/ic_superproj/aoi/Mgc_home" # "_cal_" is for handoff
ENV["CALIBRE_HOME"] = ENV["MGC_HOME"] = @mgc_home
ENV["PATH"]="#{@mgc_home}/bin:/test_suite/dfm/utils/bin/:#{ENV["PATH"]}"
ENV["LD_LIBRARY_PATH"]="#{@mgc_home}/pkgs/icv_lib/lib64:#{@mgc_home}/lib"
ENV["TEST_SUITE_TOP"]="/test_suite"
ENV["DESIGN_DIR"]="/design_dir"
# ========================================== GENERAL SETTING ========================================== #
@working_dir = %x[pwd].chomp
@db_dir = "#{@working_dir}/QA_CASE"
@script_dir = "#{@working_dir}/scripts"
@deck_dir = "#{@working_dir}/deck"
@out_gds = ENV["OUT_GDS"] = "FEOL.gds"
@out_sum = ENV["OUT_SUM"] = "FEOL_fill.sum"
@drc_out = ENV["DRC_OUT"] = "DRC_RES.gds"
@drc_sum = ENV["DRC_SUM"] = "DRC.sum"
@run_id = "run_#{wa.split('/').last}_#{Time.now.strftime("%Y%m%d-%H%M")}"
@run_dir = "#{@working_dir}/#{@run_id}"
@report_file = "#{@run_dir}/compare_drc.txt.gds"
@fill_deck = "#{@deck_dir}/SmartFillDeck"
@drc_deck = "#{@deck_dir}/DRCDeck"
# ========================================== FOLDER Check ============================================ #
Folder_Check(@deck_dir, @script_dir, @db_dir)
# ========================================== DECK SELECTION ========================================== #
@fill_deck = Get_Fill_Deck()
puts "### RUN_DRC ? (1/0)"
@run_drc = gets.chomp == "1" # true
@drc_deck = Get_Drc_Deck() if @run_drc
@drc_pre_dir = "#{@working_dir}/drc_pre/#{File.basename(@drc_deck)}/"
Make_Sure_Folder_Exist(@run_dir, @drc_pre_dir)
end
# Calibre folder selection
def Get_Calibre_Folder()
folder_list = [] +
Dir.glob("folder1") +
Dir.glob("folder2")
folder_list.each_with_index do |f,i|
exist = File.exist?("#{f}/ic/ic_superproj/aoi/Mgc_home") ? "YES" : "NO"
puts "[#{i}] [MGC_HOME:#{exist}] #{f}"
end
puts "\n### Which Calibre folder to use ? ###\n"
return folder_list[gets.chomp.to_i]
end
# Determine SmartFill Deck
def Get_Fill_Deck()
filldecks = Dir.glob("#{@deck_dir}/*CalibreYE*[^~]").reverse
filldecks.each_with_index do |f,i|
puts "[#{i}] #{f}"
end
idx = ""
until !idx.empty?
puts "\n### Which SmartFill deck to use ? ###\n"
idx = gets.chomp
end
return filldecks[idx.to_i]
end
# Determine DRC Deck
def Get_Drc_Deck()
drcdecks = Dir.glob("#{@deck_dir}/*CLN*[^~]").reverse
drcdecks.each_with_index do |f,i|
puts "[#{i}] #{f}"
end
idx = ""
until !idx.empty?
puts "\n### Which DRC deck to use ? ###\n"
idx = gets.chomp
end
return drcdecks[idx.to_i]
end
end
# ========================================== Script Start ============================================= #
conf = Conf.new
# ===================================================================================================== #
# ========================================== Information ============================================== #
# ===================================================================================================== #
LOGNAME = "#{conf.run_id}.log"
log_file = File.open(LOGNAME, "w")
logger = Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)
FILE_LIST = Get_FILE_LIST().delete_if { |f| !File.exist?("#{conf.db_dir}/#{f}") } # Specific execution order
logger.info("====================================================================================================")
logger.info("### MGC_HOME : #{ENV["MGC_HOME"]} ")
logger.info("### CALIBRE_HOME : #{ENV["CALIBRE_HOME"]} ")
logger.info("### FILL DECK : #{conf.fill_deck} ")
logger.info("### DRC DECK : #{conf.drc_deck} ") if conf.run_drc
logger.info("### DB_DIR : #{conf.db_dir} ")
logger.info("### SCRIPT : #{conf.script_dir} ")
logger.info("### DECK_DIR : #{conf.deck_dir} ")
logger.info("### RUN DIR : #{conf.run_dir} ")
logger.info("### FILE LIST : #{FILE_LIST.inspect} ")
logger.info("====================================================================================================")
# ===================================================================================================== #
# =============================================== ENV FLAG ============================================ #
# ===================================================================================================== #
ENV["CALIBRE_DFM_FILL_DEBUG_FILLABLE_REGION_OUTPUT"]="1"
# Result check file
%x[echo "#{conf.script_dir}/check.rb #{conf.drc_deck} #{conf.report_file}" > #{conf.run_id}_check.sh] if conf.run_drc
FILE_LIST.each do |cell|
tmp_deck_name = "_tmp_deck"
ENV["LAYOUT_PATH"] = $LAYOUT_PATH = "#{conf.db_dir}/#{cell}"
# TOP CELL
topcell = Get_TopCell($LAYOUT_PATH)
logger.info("[#{cell}] | TOP_CELL: #{topcell} ... ")
# Folder/File Preparation
$CELL_DIR = "#{conf.run_dir}/#{cell}"
$DRC_DIR = "#{$CELL_DIR}/drc"
$DRC_PRE_DIR = "#{conf.drc_pre_dir}/#{cell}"
Make_Sure_Folder_Exist($CELL_DIR, $DRC_DIR, $DRC_PRE_DIR)
Cleanup($CELL_DIR, conf.out_gds, conf.out_sum)
Dir.chdir($CELL_DIR)
# ========================================== SmartFill ============================================== #
logger.info("[#{cell}] | SmartFill Run ... ")
deck_name = Get_Deck($LAYOUT_PATH, conf.fill_deck, tmp_deck_name)
%x[calibre -drc -hier -turbo -hyper #{deck_name} | tee run_fill.log] if !DEBUG_RUN
logger.info("[#{cell}] | SmartFill RunTime: %s" % Get_RunTime("run_fill.log"))
Cleanup($CELL_DIR, tmp_deck_name) # Delete tmp deck if existed
# ========================================== MergeFile ============================================== #
logger.info("[#{cell}] | Merge file ... ")
merge_script = Get_Merge_Script("#{conf.script_dir}/merge_newtop.abst") # If file not exist, generate one
%x[calibredrv #{merge_script} #{$LAYOUT_PATH} #{conf.out_gds} Merged.gds | tee run_merge.log] if !DEBUG_RUN
if conf.run_drc
# ========================================== DRC Pre ============================================== #
if !File.exist?("#{$DRC_PRE_DIR}/#{conf.drc_out}")
logger.info("[#{cell}] | Pre-DRC ... ")
Dir.chdir($DRC_PRE_DIR)
deck_name = Get_Deck($LAYOUT_PATH, conf.drc_deck, tmp_deck_name)
%x[calibre -drc -hier -turbo -hyper #{deck_name} | tee run_drc.log]
logger.info("[#{cell}] | Pre-DRC Runtime: %s" % Get_RunTime("run_drc.log"))
Cleanup($CELL_DIR, tmp_deck_name) # Delete tmp deck if existed
Dir.chdir($CELL_DIR)
else
logger.info("[#{cell}] | Pre-DRC: Use #{$DRC_PRE_DIR} as reference. ")
end
%x[ln -s #{$DRC_PRE_DIR} drc_pre] # Link the drc_pre folder
# ========================================== DRC Post ============================================== #
Dir.chdir($DRC_DIR)
logger.info("[#{cell}] | Post-DRC ... ")
ENV["LAYOUT_PATH"] = $LAYOUT_PATH = "../Merged.gds"
deck_name = Get_Deck($LAYOUT_PATH, conf.drc_deck, tmp_deck_name)
%x[calibre -drc -hier -turbo -hyper #{deck_name} | tee run_drc.log]
logger.info("[#{cell}] | Post-DRC Runtime: %s" % Get_RunTime("run_drc.log"))
Cleanup($CELL_DIR, tmp_deck_name) # Delete tmp deck if existed
# ========================================== dbdiff ============================================== #
format1 = Get_Format("#{$DRC_DIR}/#{conf.drc_out}")
format2 = Get_Format("#{$DRC_PRE_DIR}/#{conf.drc_out}")
topcell1 = Get_TopCell("#{$DRC_DIR}/#{conf.drc_out}")
topcell2 = Get_TopCell("#{$DRC_PRE_DIR}/#{conf.drc_out}")
logger.info("[#{cell}] | dbdiff Stage ... ")
%x[dbdiff -system #{format1} -design #{$DRC_DIR}/#{conf.drc_out} #{topcell1} -refsystem #{format2} -refdesign #{$DRC_PRE_DIR}/#{conf.drc_out} #{topcell2} -write_xor_rules compare.svrf | tee run_dbdiff.log]
logger.info("[#{cell}] | dbdiff Runtime: %s" % Get_RunTime("run_dbdiff.log"))
if File.exist?("compare.svrf")
# ========================================== DRC Result XOR ============================================== #
logger.info("[#{cell}] | XOR Stage ... ")
sedStr='{s/DRC SUMMARY REPORT \"compare.svrf.summary\" HIER/DRC SUMMARY REPORT \"compare.svrf.summary\" \/\/HIER/g; s/DRC CELL NAME YES CELL SPACE XFORM/\/\/DRC CELL NAME YES CELL SPACE XFORM/g ; s/XOR/NOT INTERACT/g }'
%x[sed -e '#{sedStr}' compare.svrf > a]
%x[echo "LAYOUT INPUT EXCEPTION SEVERITY PATH_WIDTH_ZERO 0"|cat - a > a1]
%x[mv a1 compare.svrf]
%x[calibre -64 -drc -hier -turbo -hyper compare.svrf | tee run_compare.log]
logger.info("[#{cell}] | XOR Runtime: %s" % Get_RunTime("run_compare.log"))
# ========================================== Result Gen ============================================== #
%x[echo "--------------------------------------------" >> #{conf.report_file}]
%x[echo #{cell} >> #{conf.report_file}]
%x[grep RULECHECK #{$DRC_DIR}/compare.svrf.summary >> #{conf.report_file}]
%x[echo "--------------------------------------------" >> #{conf.report_file}]
else
logger.error("[#{cell}] | dbdiff Stage : compare.svrf is NOT generated.")
end
end
end
Dir.chdir(conf.working_dir)
logger.info("================ QA Run Completed ================\n\n")
log_file.flush # Make sure log_file have data
# Get DRC Result
if conf.run_drc
%x[sh #{conf.run_id}_check.sh >> #{conf.run_id}_RESULTS]
%x[echo ================ DRC RESULTS ================ >> #{LOGNAME}]
%x[cat #{conf.run_id}_RESULTS >> #{LOGNAME}]
log_file.flush # Make sure log_file have data
end
# Send result by email
%x[mail -s "[QA Run Result] #{conf.run_id}" "kala_kuo@xxx.com" < #{LOGNAME}]
以上是关于ruby QA使用Calibre DRC和SmartFill运行脚本的主要内容,如果未能解决你的问题,请参考以下文章