class HDLRuby::Low::Block
Describes a block.
Describes a block.
Extends the Block
class with generation of C text.
Extends the Block
class with generation of hdr text.
Add the conversion to high.
Extends the Block
class with functionality for converting par block to seq.
Extends the Block
class with generation of HDLRuby::High
text.
Extends the Block
class with functionality for converting booleans in assignments to select operators.
Extends the Block
class with functionality for extracting expressions from cast.
Extends the Block
class with functionality for breaking assingments to concats.
Extends the Block
class with fixing of types and constants.
Describes a block.
Extends Block
with the capability of finding one of its inner object by name.
Extends the Block
class with separation between signals and variables.
Extends the Block
class with functionality for breaking assingments to concats.
Extends the When
class with functionality for moving the declarations to the upper namespace.
Extends the Block
class with functionality for breaking assingments to concats.
Extends the Block
class with functionality for converting select expressions to case statements.
To scheduling to the Block
. Enhance Block
with generation of verilog code.
Attributes
The execution mode of the block.
The name of the block if any
Public Class Methods
Creates a new mode
sort of block with possible name
.
# File lib/HDLRuby/hruby_low.rb, line 3991 def initialize(mode, name = :"") super() # puts "new block with mode=#{mode} and name=#{name}" # Check and set the type. @mode = mode.to_sym # Check and set the name. @name = name.to_sym # Initializes the list of inner statements. # @inners = {} @inners = HashName.new # Initializes the list of statements. @statements = [] end
Public Instance Methods
Adds the c code of the blocks to res
at level
# File lib/HDLRuby/hruby_low2c.rb, line 1366 def add_blocks_code(res,level) res << self.to_c_code(level) end
Adds inner signal signal
.
# File lib/HDLRuby/hruby_low.rb, line 4049 def add_inner(signal) # Check and add the signal. unless signal.is_a?(SignalI) raise AnyError, "Invalid class for a signal instance: #{signal.class}" end # if @inners.has_key?(signal.name) then if @inners.include?(signal) then raise AnyError, "SignalI #{signal.name} already present." end # @inners[signal.name] = signal # Set its parent. signal.parent = self # And add it @inners.add(signal) end
Adds the creation of the blocks to res
at level
.
# File lib/HDLRuby/hruby_low2c.rb, line 1371 def add_make_block(res,level) res << " " * level*3 res << "#{Low2C.make_name(self)}();\n" end
Adds a statement
.
NOTE: TimeWait
is not supported unless for TimeBlock
objects.
# File lib/HDLRuby/hruby_low.rb, line 4099 def add_statement(statement) unless statement.is_a?(Statement) then raise AnyError, "Invalid class for a statement: #{statement.class}" end if statement.is_a?(TimeWait) then raise AnyError, "Timed statements are not supported in common blocks." end @statements << statement # And set its parent. statement.parent = self statement end
Adds variable name
with type
.
# File lib/HDLRuby/hruby_low_with_var.rb, line 137 def add_variable(name,type) # Ensure name is a symbol. name = name.to_sym # Declares the variable as an inner. inner = add_inner(SignalI.new(name,type)) # And register it as a variable. variables[name] = inner end
A method that takes a variable from the sent left side and adds “att”.
# File lib/HDLRuby/hruby_verilog.rb, line 1331 def att_sharp(left,att = "'") new_left = search_refname(left, att) return new_left end
Generate a signal for the variable to which “'” or “#” is added.
# File lib/HDLRuby/hruby_verilog.rb, line 1322 def att_signal(left,att = "'") this_name = res_name(left) new_name = RefName.new(this_name.type, this_name.ref.clone, this_name.name.to_s + att) new_signal = SignalI.new(new_name.name,new_name.type) return new_signal end
Converts the par sub blocks to seq.
# File lib/HDLRuby/hruby_low2seq.rb, line 198 def blocks2seq! # First recurse on each statement. self.each_statement { |stmnt| stmnt.blocks2seq! } # If the block is already seq, nothing more to do. return self if self.mode == :seq # IF the block contains one or less transmit statement, # simply change its mode. if self.each_statement.count { |stmnt| stmnt.is_a?(Transmit) } <= 1 self.set_mode!(:par) return self end # Gather the left values of the assignments. lvalues = self.each_statement.select do |stmnt| stmnt.is_a?(Transmit) end.map { |trans| trans.left } # Gather the right values inside the whole block. rvalues = self.each_node_deep.select do |node| node.is_a?(Expression) and node.rightvalue? end # Keep the left value that are reused. lvalues = lvalues & rvalues # Create new inner variable for replacing them. nvalues = [] lvalues.each do |lvalue| # Create the replacing variable. nvalues << nvalue = self.add_inner( SignalI.new(HDLRuby.uniq_name,lvalue.type)) # Replace it. ref = RefName.new(lvalue.type, RefThis.new, nvalues[-1].name) lvalue.parent.set_left!(ref) # And reassign it at the end of the block. lvalue.parent = nil assign = Transmit.new(lvalue,ref.clone) self.add_statement(assign) end return self end
Converts booleans in assignments to select operators.
# File lib/HDLRuby/hruby_low_bool2select.rb, line 163 def boolean_in_assign2select! # Apply on each statement. self.each_statement(&:boolean_in_assign2select!) return self end
Breaks the assignments to concats.
NOTE: work on the direct sub statement only, not deeply.
# File lib/HDLRuby/hruby_low_without_concat.rb, line 109 def break_concat_assigns! # Check each transmit. self.each_statement.each.with_index do |stmnt,i| if stmnt.is_a?(Transmit) then # Transmit, breaking may be necessary. nstmnt = stmnt.break_concat_assigns if nstmnt.is_a?(Block) then # The transmit has been broken, remove the former # version and add the generated block as a behavior. self.set_statement!(i,nstmnt) end end end end
Extracts the expressions from the casts.
# File lib/HDLRuby/hruby_low_casts_without_expression.rb, line 160 def casts_without_expression! # Apply on each statement. self.each_statement(&:casts_without_expression!) return self end
# File lib/HDLRuby/hruby_verilog.rb, line 1231 def change_branch(block) flat = Block.new(self.mode,"") # Store the expression until if is found. trans = Block.new(self.mode,"") # A block that stores the expression after if is found. new_block = Block.new(self.mode,"") # Block storing each converted expression. has_branch = false # It is true if there is an if in the block. more_has_branch = false # It is true if there are two or more if in the block. # Search each expression for if. block.each_statement do |statement| if (has_branch) trans.add_statement(statement.clone) if statement.is_a?(If) || statement.is_a?(Case) then more_has_branch = true end else if statement.is_a?(If) || statement.is_a?(Case) then flat.add_statement(statement.clone) has_branch = true else flat.add_statement(statement.clone) end end end # If there are two or more if, recursively process if. if(more_has_branch) then conversion_block = change_branch(trans) else conversion_block = trans.clone end # Store "trans" contents for "if" and "case" in "flat". flat.each_statement do |statement| # Since case statements include defaulu and when, we store the expressions saved in each case. if statement.is_a?(Case) then if statement.default.is_a?(Block) new_default = statement.default.clone conversion_block.each_statement do |smt| new_default.add_statement(smt.clone) end end new_statement = Case.new(statement.value.clone,statement.default ? new_default.clone : nil,[]) statement.each_when do |whens| new_when = whens.clone conversion_block.each_statement do |smt| new_when.statement.add_statement(smt.clone) end new_statement.add_when(new_when.clone) end new_block.add_statement(new_statement.clone) # Because there are yes, no and noifs in the if statement, store the expression saved in each. elsif statement.is_a?(If) then new_yes = statement.yes.clone conversion_block.each_statement do |smt| new_yes.add_statement(smt.clone) end if statement.no.is_a? (Block) then new_no = statement.no.clone conversion_block.each_statement do |smt| new_no.add_statement(smt.clone) end end # Make new if with converted yes and no. new_statement = If.new(statement.condition.clone,new_yes.clone,statement.no ? new_no.clone : nil) statement.each_noif do |condition, block| new_noif = block.clone conversion_block.each_statement do |smt| new_noif.add_statement(smt.clone) end new_statement.add_noif(condition.clone,new_noif.clone) end # Add the new statement (if) created to flat. new_block.add_statement(new_statement.clone) else new_block.add_statement(statement.clone) end end return new_block # Return block after conversion. end
Clones (deeply)
# File lib/HDLRuby/hruby_low.rb, line 4215 def clone # Creates the new block. nblock = Block.new(self.mode,self.name) # Duplicate its content. self.each_statement do |statement| nblock.add_statement(statement.clone) end return nblock end
Deletes an inner.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1112 def delete_inner!(signal) if @inners.key?(signal.name) then # The signal is present, delete it. @inners.delete(signal.name) # And remove its parent. signal.parent = nil end signal end
Deletes a statement.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1178 def delete_statement!(statement) if @statements.include?(statement) then # Statement is present, delete it. @statements.delete(statement) # And remove its parent. statement.parent = nil end statement end
Removes the signals and corresponding assignments whose name is not in keep
.
# File lib/HDLRuby/hruby_low_cleanup.rb, line 172 def delete_unless!(keep) # Delete the unecessary inner signals. self.each_inner.to_a.each do |inner| self.delete_inner!(inner) unless keep.include?(inner.name) end # Recurse on the sub statements. self.each_statement {|stmnt| stmnt.delete_unless!(keep) } # Delete the unecessary assignments. self.each_statement.to_a.each do |stmnt| if stmnt.is_a?(Transmit) && !stmnt.left.each_node_deep.any? { |node| node.is_a?(RefName) && keep.include?(node.name) } then self.delete_statement!(stmnt) end end end
# File lib/HDLRuby/hruby_verilog.rb, line 706 def do_flat(mode = nil) flat = Block.new(self.mode,"") # Block between lower layers when converting. trans = Block.new(self.mode,"") # The block used for converting itself. replase = Block.new(self.mode,"") # block to be used for further conversion in case of if statement. list = [] rep_list = [] # If there is a block inside the statement it is not the lowest layer. If there is, it is the lowest layer. if (self.each_statement.find {|stmnt| stmnt.is_a?(Block)} || (self.each_statement.find {|stmnt| stmnt.is_a?(If)}) || (self.each_statement.find {|stmnt| stmnt.is_a?(Case)}))then # In the case of seq, the lower layer is par. Isolate fm_par so that it is not crosstalked. if(self.mode == :seq) then fm_buckup = $fm.fm_par.clone $fm.fm_par.clear() new_block = change_branch(self) else new_block = self.clone end # Process for each statement. new_block.each_statement do |statement| # If statement is If, convert yes, no, noif and add them to flat. if statement.is_a?(Case) then if(self.mode == :seq) then fm_buckup_if = $fm.fm_par.clone end if statement.default.is_a?(Block) default = statement.default.flatten new_default = Block.new(default.mode,"") default.each_statement do |statement| new_default.add_statement(statement.clone) end end new_statement = Case.new(statement.value.clone,statement.default ? new_default.clone : nil,[]) statement.each_when do |whens| if(self.mode == :seq) then fm_buckup_if.each_key do |key| $fm.fm_par[key] = fm_buckup_if[key] end end when_smt = whens.statement.flatten new_when = When.new(whens.match.clone,when_smt.clone) new_statement.add_when(new_when.clone) end flat.add_statement(new_statement) elsif statement.is_a?(If) then if(self.mode == :seq) then fm_buckup_if = $fm.fm_par.clone end # Since yes always exist, convert without confirming. new_yes = statement.yes.flatten # I do not know whether no (else) exists, so convert it if it is confirmed. if statement.no.is_a? (Block) then if(self.mode == :seq) then fm_buckup_if.each_key do |key| $fm.fm_par[key] = fm_buckup_if[key] end end new_no = statement.no.flatten end # Create a new if statement with converted yes and no. new_statement = If.new(statement.condition.clone,new_yes.clone,statement.no ? new_no.clone : nil) # Since I do not know whether there is noifs (elsif), I convert it and add it if it is confirmed. statement.each_noif do |condition, block| if(self.mode == :seq) then fm_buckup_if.each_key do |key| $fm.fm_par[key] = fm_buckup_if[key] end end new_noif = block.flatten new_statement.add_noif(condition.clone,new_noif.clone) end # Add the new statement (if statement) created to flat. flat.add_statement(new_statement.clone) # If statement is Transmit, record the expression in fm_par and add the expression to flat as it is. elsif statement.is_a?(Transmit) then if(self.mode == :seq) then $fm.fm_par["#{statement.left.to_verilog}"] = statement.right.clone end flat.add_statement(statement.clone) # If statement is Block, convert it with do_flat and add the returned expression and variable to flat respectively. elsif statement.is_a?(Block) then smt = statement.do_flat(self.mode) # If smt has inner, check it separately and add it if it's convenient. smt.each_inner do |inner| if self.mode == :seq then unless (list.include?(inner.name.to_s)) then list << inner.name.to_s flat.add_inner(inner.clone) end else unless (list.include?(inner.name.to_s)) then if(inner.name.to_s.include? "#") then list << inner.name.to_s flat.add_inner(inner.clone) # It was new_block. why? end end end end # If it is seq, the expression after conversion is also likely to be used, so record the expression. smt.each_statement do |tmt| if self.mode == :seq then $fm.fm_par["#{tmt.left.to_verilog}"] = tmt.right.clone end flat.add_statement(tmt.clone) end end end # Overwrite to restore fm_par which was quarantined. if(self.mode == :seq) then $fm.fm_par.clear() fm_buckup.each_key do |key| $fm.fm_par[key] = fm_buckup[key] end end # Since it is a middle tier itself, it performs flat transformation, shifts inner, and returns the result. trans = flat.to_conversion(mode) # Write an expression that assigns an identifier that added # to an identifier that has not added. trans.each_statement do |statement| replase.add_statement(statement.clone) if statement.is_a?(If) $fm.rep_sharp.each_key do |key| new_statement = Transmit.new(key.clone,$fm.rep_sharp[key].clone) replase.add_statement(new_statement.clone) end $fm.rep_sharp.clear() # Deactivate rep that has become obsolete. end end # Extract the inner left in flat and add it to replase. flat.each_inner do |inner| replase.add_inner(inner.clone) end # Extract the inner left in trans and add it to replase. trans.each_inner do |inner| replase.add_inner(inner.clone) end return replase # Processing when there is no block (reaching the bottom layer). else # Since it is the lowest layer, it does not smooth but converts itself and returns it. flat = self.to_conversion(mode) return flat end end
Iterates over the sub blocks.
# File lib/HDLRuby/hruby_low.rb, line 4165 def each_block(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_block) unless ruby_block # A ruby block? # Apply it on each statement which contains blocks. self.each_statement do |statement| ruby_block.call(statement) if statement.is_a?(Block) end end
Iterates over all the blocks contained in the current block.
# File lib/HDLRuby/hruby_low.rb, line 4176 def each_block_deep(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_block_deep) unless ruby_block # A ruby block? # Apply it on self. ruby_block.call(self) # And apply it on each statement which contains blocks. self.each_statement do |statement| statement.each_block_deep(&ruby_block) end end
Iterates over each object deeply.
Returns an enumerator if no ruby block is given.
# File lib/HDLRuby/hruby_low.rb, line 4008 def each_deep(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_deep) unless ruby_block # A ruby block? First apply it to current. ruby_block.call(self) # Then apply on the inners. self.each_inner do |inner| inner.each_deep(&ruby_block) end # Then apply on the statements. self.each_statement do |stmnt| stmnt.each_deep(&ruby_block) end end
Iterates over the inner signals.
Returns an enumerator if no ruby block is given.
# File lib/HDLRuby/hruby_low.rb, line 4069 def each_inner(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_inner) unless ruby_block # A ruby block? Apply it on each inner signal instance. @inners.each(&ruby_block) end
Iterates over all the stamements of the block and its sub blocks.
# File lib/HDLRuby/hruby_low.rb, line 4202 def each_node_deep(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_node_deep) unless ruby_block # A ruby block? # Apply it on current. ruby_block.call(self) # And apply it on each statement deeply. self.each_statement do |stmnt| stmnt.each_node_deep(&ruby_block) end end
Iterates over all the signals of the block and its sub block's ones.
# File lib/HDLRuby/hruby_low.rb, line 4084 def each_signal_deep(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_signal_deep) unless ruby_block # A ruby block? # First, apply on the signals of the block. self.each_signal(&ruby_block) # Then apply on each sub block. self.each_block_deep do |block| block.each_signal_deep(&ruby_block) end end
Iterates over the statements.
Returns an enumerator if no ruby block is given.
# File lib/HDLRuby/hruby_low.rb, line 4140 def each_statement(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_statement) unless ruby_block # A ruby block? Apply it on each statement. @statements.each(&ruby_block) end
Iterates over all the stamements of the block and its sub blocks.
# File lib/HDLRuby/hruby_low.rb, line 4189 def each_statement_deep(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:each_statement_deep) unless ruby_block # A ruby block? # Apply it on current. ruby_block.call(self) # And apply it on each statement deeply. self.each_statement do |statement| statement.each_statement_deep(&ruby_block) end end
Comparison for hash: structural comparison.
# File lib/HDLRuby/hruby_low.rb, line 4024 def eql?(obj) return false unless obj.is_a?(Block) return false unless @mode.eql?(obj.mode) return false unless @name.eql?(obj.name) idx = 0 obj.each_inner do |inner| return false unless @inners[inner.name].eql?(inner) idx += 1 end return false unless idx == @inners.size idx = 0 obj.each_statement do |statement| return false unless @statements[idx].eql?(statement) idx += 1 end return false unless idx == @statements.size return true end
Explicit the types conversions in the block.
# File lib/HDLRuby/hruby_low_fix_types.rb, line 177 def explicit_types! # Recurse on the statements. self.each_statement(&:explicit_types!) return self end
Extract the declares from the scope and returns them into an array.
NOTE: do not recurse into the sub scopes or behaviors!
# File lib/HDLRuby/hruby_low_without_namespace.rb, line 686 def extract_declares! # Ensure there is a name. self.force_name! # The extracted declares. decls = [] # Extract the inners. self.each_inner {|inner| decls << inner } decls.each {|inner| self.delete_inner!(inner) } # Renames them with the current level. decls.each do |inner| former = inner.name self.extend_name!(inner) self.replace_names_subs!(former,inner.name) end # Returns the extracted declares. return decls end
Extract the variables corresponding to external signals from block-based statement stmnt
, and put the extraction result is table sym2var
that associate variable with corresponding signal name.
# File lib/HDLRuby/hruby_low_with_var.rb, line 82 def extract_from_externals!(stmnt,sym2var) if (stmnt.is_a?(Block)) then # Block case, gather its declared and signals variables. vars = {} sigs = {} stmnt.each_inner do |inner| if variable_name?(inner.name) then vars[inner.name] = inner else sigs[inner.name] = inner end end # Select the variables that correspond to external signals. vars.each do |name,inner| sym = var_name2sym(name) unless sigs.key?(sym) then # The variable correspond to an external signal, # extract it. sym2var[sym] = inner stmnt.delete_inner(inner) end end elsif # Other case, recurse on the sub blocks. stmnt.each_block do |block| extract_from_externals!(block,sym2var) end end end
Process top layer of Block
. Determine whether there is a block under block and convert it.
# File lib/HDLRuby/hruby_verilog.rb, line 243 def flatten(mode = nil) if self.is_a?(TimeBlock) then new_block = TimeBlock.new(self.mode,"") else new_block = Block.new(self.mode,"") # A new block to store the converted statement. end list = [] # A list for confirming that variable declarations do not overlap. # Is block in the statement? if (self.each_statement.find {|stmnt| stmnt.is_a?(Block)}) then # Process for each type of statement in block. self.each_statement do |statement| # If statement is case, there is a block for each default and when, so translate each. if statement.is_a?(Case) then if statement.default.is_a?(Block) default = statement.default.flatten new_default = Block.new(default.mode,"") default.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (self.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end default.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || default.mode == :par then # Prepare a new signal with the # on the variable on the left side using the att_signal method. new_signal = att_signal(statement.left, "#") # Check list and add new variables to inner if they do not duplicate. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_statement.left new_default.add_statement(new_statement.clone) else new_default.add_statement(statement.clone) end else new_default.add_statement(statement.clone) end end end new_statement = Case.new(statement.value.clone,statement.default ? new_default.clone : nil,[]) statement.each_when do |whens| when_smt = whens.statement.flatten new_when_smt = Block.new(when_smt.mode,"") when_smt.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || when_smt.mode == :par then # # Prepare a new signal with the # on the variable on the left side using the att_signal method. new_signal = att_signal(statement.left, "#") # Check list and add new variables to inner if they do not duplicate. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_smt = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_smt.left new_when_smt.add_statement(new_smt.clone) else new_when_smt.add_statement(statement.clone) end else new_when_smt.add_statement(statement.clone) end end new_when = When.new(whens.match.clone,new_when_smt.clone) new_statement.add_when(new_when.clone) end new_block.add_statement(new_statement) $fm.rep_sharp.each_key do |key| new_smt = Transmit.new(key.clone,$fm.rep_sharp[key].clone) new_block.add_statement(new_smt.clone) end $fm.rep_sharp.clear() # Deactivate rep that has become obsolete. # If the statement is if, there is a block for each of yes, no, noifs, so translate each. elsif statement.is_a?(If) then yes = statement.yes.flatten # Smooth yes of if statement. new_yes = Block.new(yes.mode,"") # New yes storage block yes.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (self.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end # Check the statements in "yes" in order. yes.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || yes.mode == :par then # Prepare a new signal with the # on the variable on the left side using the att_signal method. new_signal = att_signal(statement.left, "#") # Check list and add new variables to inner if they do not duplicate. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") new_yes.add_statement(new_statement.clone) $fm.fm_par["#{statement.left.to_verilog}"] = new_statement.left else new_yes.add_statement(statement.clone) end else new_yes.add_statement(statement.clone) end end # Confirm that "else" exists and convert it if it exists. # Because error occurs when trying to convert when "else" does not exist. if statement.no.is_a? (Block) then no = statement.no.flatten new_no = Block.new(no.mode,"") no.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (self.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end no.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || yes.mode == :par then new_signal = att_signal(statement.left, "#") # Double declaration of existing variable can not be done, so it is excluded. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_statement.left new_no.add_statement(new_statement.clone) else new_no.add_statement(statement.clone) end else new_no.add_statement(statement.clone) end end end # Rebuild the converted "if" as a new" statement (If)". new_statement = If.new(statement.condition.clone,new_yes.clone,statement.no ? new_no.clone : nil) # Just like "no", check if "noifs (elsif)" exists and if there is, take one by one and convert. # After that, add the converted "noif" to "If". statement.each_noif do |condition, block| noif = block.flatten new_noif = Block.new(noif.mode,"") noif.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (self.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end noif.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || yes.mode == :par then new_signal = att_signal(statement.left, "#") # Double declaration of existing variable can not be done, so it is excluded. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_statement.left new_noif.add_statement(new_statement.clone) else new_noif.add_statement(statement.clone) end else new_noif.add_statement(statement.clone) end end new_statement.add_noif(condition.clone,new_noif.clone) end new_block.add_statement(new_statement.clone) $fm.rep_sharp.each_key do |key| new_smt = Transmit.new(key.clone,$fm.rep_sharp[key].clone) new_block.add_statement(new_smt.clone) end $fm.rep_sharp.clear() # Deactivate rep that has become obsolete. # Process when "statement" is "Transmit" (just expression). # Record the expression in fm_par used for par-> seq and add the expression to new_block which is the "new block". elsif statement.is_a?(Transmit) then if self.mode == :seq then $fm.fm_par["#{statement.left.to_verilog}"] = statement.right end new_block.add_statement(statement.clone) # When statement is Block (lower layer exists). # Smooth the lower layer with do_flat. # Add the added variables (inner) and expressions (statement) to new_block, respectively. elsif statement.is_a?(Block) then smt = statement.do_flat(self.mode) smt.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (self.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end smt.each_statement do |tmt| # Retrieve the RefName of the variable on the left side and store it in this_name. if ((tmt.is_a? (Transmit)) && (self.mode == :seq)) then $fm.fm_par["#{tmt.left.to_verilog}"] = tmt.right end new_block.add_statement(tmt.clone) end else # Other statements are simply added as is. new_block.add_statement(statement.clone) end end return new_block # Return the new_block that completed the smoothing. # Processing when there is no block beneath. # Unlike ordinary "if" and "case" blocks come down, we check individually block under block. else self.each_statement do |statement| # If the if statement, convert it, otherwise add it as is if statement.is_a?(If) then # Since yes always exists, it is no problem even if it is converted as it is. yes = statement.yes.flatten new_yes = Block.new(yes.mode,"") yes.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (yes.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end # Check the statements in "yes" in order. yes.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || yes.mode == :par then # Generate a new signal to return #. new_signal = att_signal(statement.left, "#") # Double declaration of existing variable can not be done, so it is excluded. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_statement.left new_yes.add_statement(new_statement.clone) else new_yes.add_statement(statement.clone) end else new_yes.add_statement(statement.clone) end end # Confirm that "else" exists and convert it if it exists. # Because error occurs when trying to convert when "else" does not exist. if statement.no.is_a? (Block) then no = statement.no.flatten new_no = Block.new(no.mode,"") no.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (no.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end no.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || no.mode == :par then new_signal = att_signal(statement.left, "#") # Double declaration of existing variable can not be done, so it is excluded. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_statement.left new_no.add_statement(new_statement.clone) else new_no.add_statement(statement.clone) end else new_no.add_statement(statement.clone) end end end # Rebuild the converted "if" as a new" statement (If)". new_statement = If.new(statement.condition.clone,new_yes.clone,statement.no ? new_no.clone : nil) # Just like "no", check if "noifs (elsif)" exists and if there is, take one by one and convert. # After that, add the converted "noif" to "If". statement.each_noif do |condition, block| noif = block.flatten new_noif = Block.new(noif.mode,"") noif.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (noif.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s new_block.add_inner(inner.clone) end end end noif.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || noif.mode == :par then new_signal = att_signal(statement.left, "#") # Double declaration of existing variable can not be done, so it is excluded. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s new_block.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_statement.left new_noif.add_statement(new_statement.clone) else new_noif.add_statement(statement.clone) end else new_noif.add_statement(statement.clone) end end new_statement.add_noif(condition.clone,new_noif.clone) end new_block.add_statement(new_statement.clone) $fm.rep_sharp.each_key do |key| new_smt = Transmit.new(key.clone,$fm.rep_sharp[key].clone) new_block.add_statement(new_smt.clone) end $fm.rep_sharp.clear() # Deactivate rep that has become obsolete. elsif statement.is_a?(Case) then if statement.default.is_a?(Block) new_default = statement.default.flatten end new_statement = Case.new(statement.value.clone,statement.default ? new_default.clone : nil,[]) statement.each_when do |whens| new_when_statement = whens.statement.flatten new_when = When.new(whens.match.clone,new_when_statement.clone) new_statement.add_when(new_when.clone) end new_block.add_statement(new_statement) else new_block.add_statement(statement.clone) end end return new_block end end
Find an inner object by name
. NOTE: return nil if not found.
# File lib/HDLRuby/hruby_low_resolve.rb, line 78 def get_by_name(name) # Ensure the name is a symbol. name = name.to_sym # Look in the signals. return self.get_inner(name) end
Gets an inner signal by name
.
# File lib/HDLRuby/hruby_low.rb, line 4078 def get_inner(name) return @inners[name.to_sym] end
Gets a variable by name
.
# File lib/HDLRuby/hruby_low_with_var.rb, line 147 def get_variable(name) # Ensure name is a symbol. name = name.to_sym # Get the variable. return variables[name] end
Hash
function.
# File lib/HDLRuby/hruby_low.rb, line 4044 def hash return [@mode,@name,@inners,@statements].hash end
Inserts statement *stmnt+ at index idx
.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1123 def insert_statement!(idx,stmnt) # Checks the index. if idx > @statements.size then raise AryError, "Index out of range: #{idx}" end # Checks the statement. unless stmnt.is_a?(Statement) raise AnyError, "Invalid type for a statement: #{stmnt.class}" end # Inserts the statement. @statements.insert(idx,stmnt) stmnt.parent = self end
Returns the last statement.
# File lib/HDLRuby/hruby_low.rb, line 4160 def last_statement return @statements[-1] end
Maps on the inners.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1103 def map_inners!(&ruby_block) @inners.map! do |inner| inner = ruby_block.call(inner) inner.parent = self unless inner.parent inner end end
Maps on the statements.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1167 def map_statements!(&ruby_block) @statements.map! do |stmnt| stmnt = ruby_block.call(stmnt) stmnt.parent = self unless stmnt.parent stmnt end end
Tell if there is a mix block. mode
is the mode of the upper block.
# File lib/HDLRuby/hruby_low2seq.rb, line 238 def mix?(mode = nil) # Check if different from mode block if any. return true if mode && self.type != mode # No difference with the upper block, maybe there is one within. # Check each statement. self.each_statement.any? { |stmt| stmnt.mix?(mode) } end
Gets the number of statements.
# File lib/HDLRuby/hruby_low.rb, line 4133 def num_statements return @statements.size end
Converts par blocks within seq blocks to seq blocks.
# File lib/HDLRuby/hruby_low_without_parinseq.rb, line 106 def par_in_seq2seq! # Recurse on the sub blocks. self.each_statement(&:par_in_seq2seq!) # Is the current block a seq block? if self.mode == :seq then # Yes, convert its inner par blocks to seq blocks. self.each_statement do |statement| if (statement.is_a?(Block)) then statement.to_seq! if statement.mode == :par end end end return self end
Replace node by corresponding replacement from node2reassign
that is a table whose entries are: node
the node to replace rep
the replacement of the node ref
the reference where to reassign the node.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1208 def reassign_expressions!(node2reassign) # Build the replacement table. node2rep = node2reassign.map {|n,r| [n,r[0]] }.to_h # First recurse on the sub blocks. # self.each_block { |block| block.reassign_expressions!(node2rep) } self.each_block { |block| block.reassign_expressions!(node2reassign) } # Now work on the block. # Replace on the statements. self.map_statements! do |statement| # Do the replacement node2rep_done = statement.replace_expressions!(node2rep) # Assign the replaced nodes in a new block. unless node2rep_done.empty? blk = Block.new(:seq) node2rep_done.each do |node,rep| reassign = node2reassign[node][1].clone blk.add_statement(Transmit.new(reassign,node.clone)) end blk.add_statement(statement.clone) blk else statement end end end
Replaces the references by corresponding variables in stmnt
from sym2var
table.
# File lib/HDLRuby/hruby_low_with_var.rb, line 115 def refs_by_variables!(stmnt,sym2var) # First, recurse. if stmnt.respond_to?(:each_node) then stmnt.each_node {|elem| refs_by_variables!(elem,sym2var) } end # Now replace an element if required. if stmnt.respond_to?(:map_nodes!) then stmnt.map_nodes! do |elem| var = sym2var[elem.to_sym] var ? var2ref(var) : elem end end end
Extract and convert to verilog the TimeRepeat
statements. NOTE: work only on the current level of the block (should be called through each_block_deep
).
# File lib/HDLRuby/hruby_verilog.rb, line 188 def repeat_to_verilog! code = "" # Gather the TimeRepeat statements. repeats = self.each_statement.find_all { |st| st.is_a?(TimeRepeat) } # Remove them from the block. repeats.each { |st| self.delete_statement!(st) } # Generate them separately in timed always processes. repeats.each do |st| code << " always #{st.delay.to_verilog} begin\n" # Perform "scheduling" using the method "flatten". block = st.statement.flatten(st.statement.mode.to_s) # Declaration of "inner" part within "always". block.each_inner do |inner| # if regs.include?(inner.name) then if HDLRuby::Low::VERILOG_REGS.include?(inner.to_verilog) then code << " reg" else code << " wire" end # Variable has "base", but if there is width etc, it is not in "base". # It is determined by an if. if inner.type.base? if inner.type.base.base? code << "#{inner.type.base.to_verilog} #{inner.to_verilog} #{inner.type.to_verilog}" else code << "#{inner.type.to_verilog} #{inner.to_verilog}" end else code << " #{inner.type.to_verilog}#{inner.to_verilog}" end if inner.value then # There is an initial value. code << " = #{inner.value.to_verilog}" end code << ";\n" end # Translate the block that finished scheduling. block.each_statement do |statement| code << "\n #{statement.to_verilog(block.mode.to_s)}" end $fm.fm_par.clear() code << "\n end\n\n" end return code end
Replaces sub expressions using node2rep
table indicating the node to replace and the corresponding replacement. Returns the actually replaced nodes and their corresponding replacement.
NOTE: the replacement is duplicated.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1194 def replace_expressions!(node2rep) res = {} # Recurse on the children. self.each_node do |node| res.merge!(node.replace_expressions!(node2rep)) end return res end
Replaces recursively former
name by nname
until it is redeclared.
# File lib/HDLRuby/hruby_low_without_namespace.rb, line 713 def replace_names!(former,nname) # Stop here if the name is redeclared. return if self.each_inner.find {|inner| inner.name == former } # Recurse on the sub scopes and behaviors. replace_names_subs!(former,nname) end
Replaces recursively former
name by nname
until it is redeclared in the sub scopes and behaviors.
# File lib/HDLRuby/hruby_low_without_namespace.rb, line 706 def replace_names_subs!(former,nname) self.each_statement do |stmnt| stmnt.replace_names!(former,nname) end end
Replaces statement org
by statement stmnt
.
NOTE: does nothing if org
is not present.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1157 def replace_statement!(org,stmnt) # Checks the statement. unless stmnt.is_a?(Statement) raise AnyError, "Invalid type for a statement: #{stmnt.class}" end idx = @statements.index(org) @statements[idx] = stmnt if idx end
Recursively search, return Refname.
# File lib/HDLRuby/hruby_verilog.rb, line 1353 def res_name(me) if me.is_a? (RefName) then return me else if me.ref.is_a? (RefName) then return RefName.new(me.ref.type, me.ref.ref.clone, me.ref.name.to_s) elsif me.ref.is_a? (RefIndex) then return res_name(me.ref) elsif me.ref.is_a? (RefRange) then return res_name(me.ref) end end end
Reverse iterates over the statements.
Returns an enumerator if no ruby block is given.
# File lib/HDLRuby/hruby_low.rb, line 4152 def reverse_each_statement(&ruby_block) # No ruby block? Return an enumerator. return to_enum(:reverse_each_statement) unless ruby_block # A ruby block? Apply it on each statement. @statements.reverse_each(&ruby_block) end
Recursively search, add “att” to RefName
and return.
# File lib/HDLRuby/hruby_verilog.rb, line 1339 def search_refname(me,att = "'") if me.is_a? (RefName) then return RefName.new(me.type, me.ref.clone, me.name.to_s + att) elsif me.ref.is_a? (RefName) then return RefName.new(me.ref.type, me.ref.ref.clone, me.ref.name.to_s + att) elsif me.ref.is_a? (RefIndex) then return RefIndex.new(me.ref.type, search_refname(me.ref), me.ref.index.clone) elsif me.ref.is_a? (RefRange) then my_range = me.ref.range return RefRange.new(me.ref.type, search_refname(me.ref), my_range.first.clone..my_range.last.clone) end end
Breaks the assignments to concats.
NOTE: work on the direct sub statement only, not deeply.
# File lib/HDLRuby/hruby_low_without_select.rb, line 134 def select2case! # Check each statement. self.map_statements! do |stmnt| # Skip blocks that are treated through recursion. next stmnt if stmnt.is_a?(Block) # Work on the statement. # Extract the Select expressions. selects = stmnt.extract_selects! if selects.any? then # Generate a sequential block containing the cases. blk = LowWithoutSelect.selects2block(selects) # Adds the statement to the block. blk.add_statement(stmnt.clone) stmnt = blk end stmnt end end
Sets the mode.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1091 def set_mode!(mode) # Check and set the type. @mode = mode.to_sym end
Sets the name.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1097 def set_name!(name) # Check and set the name. @name = name.to_sym end
Sets statement stmnt
at index idx
.
# File lib/HDLRuby/hruby_low_mutable.rb, line 1138 def set_statement!(idx,stmnt) # Checks the index. if idx > @statements.size then raise AryError, "Index out of range: #{idx}" end # Checks the statement. unless stmnt.is_a?(Statement) raise AnyError, "Invalid type for a statement: #{stmnt.class}" end # Detach the previous statement if any. @statements[idx].parent = nil if @statements[idx] # Set the new statement. @statements[idx] = stmnt stmnt.parent = self end
Converts symbol sym
representing an HDLRuby
reference to a variable name.
# File lib/HDLRuby/hruby_low_with_var.rb, line 63 def sym2var_name(sym) return ("%" + sym.to_s).to_sym end
Generates the execution of the block C text of the equivalent HDLRuby
code. level
is the hierachical level of the object.
# File lib/HDLRuby/hruby_low2c.rb, line 1474 def to_c(level = 0) res = " " * (level) res << "#{Low2C.code_name(self)}();\n" return res end
Generates the C text of the equivalent HDLRuby
code. level
is the hierachical level of the object.
# File lib/HDLRuby/hruby_low2c.rb, line 1378 def to_c_code(level = 0) # The resulting string. res = "" # puts "generating self=#{self.object_id}" # Declare the global variable holding the block. res << "Block #{Low2C.obj_name(self)};\n\n" # Generate the c code of the sub blocks if any. self.each_statement do |stmnt| stmnt.add_blocks_code(res,level) end # Generate the execution function. res << " " * level*3 res << "void #{Low2C.code_name(self)}() {\n" # res << "printf(\"Executing #{Low2C.code_name(self)}...\\n\");" # Generate the statements. self.each_statement do |stmnt| res << stmnt.to_c(level+1) end # Close the execution function. res << " " * level*3 res << "}\n\n" # Generate the signals. self.each_signal { |signal| res << signal.to_c(level) } # The header of the block. res << " " * level*3 res << "Block #{Low2C.make_name(self)}() {\n" res << " " * (level+1)*3 res << "Block block = malloc(sizeof(BlockS));\n" res << " " * (level+1)*3 res << "block->kind = BLOCK;\n"; # Sets the global variable of the block. res << "\n" res << " " * (level+1)*3 res << "#{Low2C.obj_name(self)} = block;\n" # Set the owner if any. if self.parent then # Look for a block or behavior parent. true_parent = self.parent until true_parent.is_a?(Block) || true_parent.is_a?(Behavior) true_parent = true_parent.parent end # Set it as the real parent. res << " " * (level+1)*3 res << "block->owner = (Object)" + "#{Low2C.obj_name(true_parent)};\n" else res << "block->owner = NULL;\n" end # The name res << " " * (level+1)*3 res << "block->name = \"#{self.name}\";\n" # Add the inner signals declaration. res << " " * (level+1)*3 res << "block->num_inners = #{self.each_inner.to_a.size};\n" res << " " * (level+1)*3 res << "block->inners = calloc(sizeof(SignalI)," + "block->num_inners);\n" self.each_inner.with_index do |inner,i| res << " " * (level+1)*3 res << "block->inners[#{i}] = " + "#{Low2C.make_name(inner)}();\n" end # Sets the execution function. res << " " * (level+1)*3 res << "block->function = &#{Low2C.code_name(self)};\n" # Generate creation of the sub blocks. self.each_statement do |stmnt| stmnt.add_make_block(res,level+1) end # Generate the Returns of the result. res << "\n" res << " " * (level+1)*3 res << "return block;\n" # Close the block. res << " " * level*3 res << "};\n\n" return res end
Generates the content of the h file.
# File lib/HDLRuby/hruby_low2c.rb, line 1481 def to_ch # puts "to_ch for block=#{Low2C.obj_name(self)} with=#{self.each_inner.count} inners" res = "" # Declare the global variable holding the block. res << "extern Block #{Low2C.obj_name(self)};\n\n" # Generate the access to the function making the block. */ res << "extern Block #{Low2C.make_name(self)}();\n\n" # Generate the accesses to the ports. self.each_inner { |inner| res << inner.to_ch } # Recurse on the statements. self.each_statement { |stmnt| res << stmnt.to_ch } return res end
# File lib/HDLRuby/hruby_verilog.rb, line 877 def to_conversion(mode = nil, rst = true, rep = true) flat = Block.new(mode,"") # Block that stores results. new_yes = Block.new(mode,"") # Block containing the new yes. new_no = Block.new(mode,"") # Block containing the new no. new_noif = Block.new(mode,"") # Block containing the new noif. list = [] if rst == false then fm_seq_backup = $fm.fm_seq.dup end # The statement is divided (since it is the lowest layer, there is only Transmit). self.each_statement do |statement| # Various processing is performed depending on the type of Transmit. # If the mode of the upper layer = its own mode, it compresses as it is. if(mode == self.mode) then new_statement = statement.clone # In the case of an If statement, processing of if, else, elsif is performed. elsif statement.is_a?(Case) then if statement.default.is_a?(Block) rep_buckup = $fm.rep.dup $fm.rep.clear() default = statement.default.to_conversion(mode,false,false) $fm.rep.clear() rep_buckup.each_key do |key| $fm.rep[key] = rep_buckup[key] end new_default = Block.new(default.mode,"") default.each_inner do |inner| # I read inner, but when I am par, I delete all '. unless (list.include?(inner.name.to_s)) then if (self.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s flat.add_inner(inner.clone) end end end default.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || default.mode == :par then # Prepare a new signal with the # on the variable on the left side using the att_signal method. new_signal = att_signal(statement.left, "#") # Check list and add new variables to inner if they do not duplicate. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s flat.add_inner(new_signal) end new_smt = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_smt.left new_default.add_statement(new_smt.clone) else new_default.add_statement(statement.clone) end else new_default.add_statement(statement.clone) end end end new_statement = Case.new(statement.value.clone,statement.default ? new_default.clone : nil,[]) statement.each_when do |whens| rep_buckup = $fm.rep.dup $fm.rep.clear() when_smt = whens.statement.to_conversion(mode,false,false) $fm.rep.clear() rep_buckup.each_key do |key| $fm.rep[key] = rep_buckup[key] end new_when_smt = Block.new(when_smt.mode,"") when_smt.each_statement do |statement| # If statement is Transmit, it is an expression and should be processed. if statement.is_a?(Transmit) then # If you add a # to the one with 'on the left side, the shape of the formula will collapse and it will be removed. unless (res_name(statement.left).name.to_s.include? "'") || when_smt.mode == :par then # Prepare a new signal with the # on the variable on the left side using the att_signal method. new_signal = att_signal(statement.left, "#") # Check list and add new variables to inner if they do not duplicate. unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s flat.add_inner(new_signal) end new_smt = Transmit.new(search_refname(statement.left,"#"),statement.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{statement.left.to_verilog}"] = new_smt.left new_when_smt.add_statement(new_smt.clone) else new_when_smt.add_statement(statement.clone) end else new_when_smt.add_statement(statement.clone) end end new_when = When.new(whens.match.clone,new_when_smt.clone) new_statement.add_when(new_when.clone) end elsif statement.is_a?(If) then rep_buckup = $fm.rep.dup $fm.rep.clear() yes = statement.yes.to_conversion(mode, false,false) $fm.rep.clear() rep_buckup.each_key do |key| $fm.rep[key] = rep_buckup[key] end yes.each_inner do |inner| unless (list.include?(inner.name.to_s)) then if (yes.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s flat.add_inner(inner.clone) # It was new_block. why? end end end yes.each_statement do |smt| if(yes.mode == :seq) then new_signal = att_signal(smt.left, "#") unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s flat.add_inner(new_signal) end yes_statement = Transmit.new(search_refname(smt.left,"#"),smt.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{smt.left.to_verilog}"] = yes_statement.left new_yes.add_statement(yes_statement) else new_yes.add_statement(smt.clone) end end if statement.no.is_a? (Block) then rep_buckup = $fm.rep.dup $fm.rep.clear() no = statement.no.to_conversion(mode,false,false) $fm.rep.clear() rep_buckup.each_key do |key| $fm.rep[key] = rep_buckup[key] end no.each_inner do |inner| unless (list.include?(inner.name.to_s)) then if (no.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s flat.add_inner(inner.clone) # It was new_block. why? end end end no.each_statement do |smt| if(no.mode == :seq) then new_signal = att_signal(smt.left, "#") unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s flat.add_inner(new_signal) end no_statement = Transmit.new(search_refname(smt.left,"#"),smt.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{smt.left.to_verilog}"] = no_statement.left new_no.add_statement(no_statement) else new_no.add_statement(smt.clone) end end end new_statement = If.new(statement.condition.clone,new_yes.clone,statement.no ? new_no.clone : nil) statement.each_noif do |condition, block| rep_buckup = $fm.rep.dup $fm.rep.clear() noif = block.to_conversion(mode,false,false) $fm.rep.clear() rep_buckup.each_key do |key| $fm.rep[key] = rep_buckup[key] end noif.each_inner do |inner| unless (list.include?(inner.name.to_s)) then if (noif.mode == :seq) || (inner.name.to_s.include? "#") then list << inner.name.to_s flat.add_inner(inner.clone) # It was new_block. why? end end end noif.each_statement do |smt| if(noif.mode == :seq) then new_signal = att_signal(smt.left, "#") unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s flat.add_inner(new_signal) end noif_statement = Transmit.new(search_refname(smt.left,"#"),smt.right.clone) $fm.rep_sharp[statement.left] = search_refname(statement.left,"#") $fm.fm_par["#{smt.left.to_verilog}"] = noif_statement.left new_noif.add_statement(no_statement) else new_noif.add_statement(smt.clone) end end new_statement.add_noif(condition.clone,new_noif.clone) end # Otherwise, it is necessary to process par-> seq or seq-> par. else # Make sure the right side is a formula (Binary). if statement.right.is_a?(Binary) then # Check the right side and the left side, and if they are variables, check the corresponding expressions and replace them. # If it is not a variable, it calls the method to be searched. if statement.right.left.is_a? (Ref) then if (mode == :par && self.mode == :seq) && $fm.fm_seq.has_key?(statement.right.left.to_verilog) then statement_left = $fm.fm_seq["#{statement.right.left.to_verilog}"] elsif (mode == :seq && self.mode == :par) && $fm.fm_par.has_key?(statement.right.left.to_verilog) then statement_left = $fm.fm_par["#{statement.right.left.to_verilog}"] else statement_left = statement.right.left.clone end elsif statement.right.left.is_a? (Binary) then statement_left = statement.right.left.to_change(self.mode) else statement_left = statement.right.left.clone end if statement.right.right.is_a? (Ref) then if (mode == :par && self.mode == :seq) && $fm.fm_seq.has_key?(statement.right.right.to_verilog) then statement_right = $fm.fm_seq["#{statement.right.right.to_verilog}"] elsif (mode == :seq && self.mode == :par) && $fm.fm_par.has_key?(statement.right.right.to_verilog) then statement_right = $fm.fm_par["#{statement.right.right.to_verilog}"] else statement_right = statement.right.right.clone end elsif statement.right.right.is_a? (Binary) then statement_right = statement.right.right.to_change(self.mode) else statement_right = statement.right.right.clone end new_right = Binary.new(statement.right.type,statement.right.operator,statement_left.clone,statement_right.clone) # Confirm whether it is a variable. elsif statement.right.is_a?(Ref) then if (mode == :par && self.mode == :seq) && $fm.fm_seq.has_key?(statement.right.to_verilog) then new_right = $fm.fm_seq["#{statement.right.to_verilog}"].clone elsif (mode == :seq && self.mode == :par) && $fm.fm_par.has_key?(statement.right.to_verilog) then new_right = $fm.fm_par["#{statement.right.to_verilog}"].clone else new_right = statement.right.clone end # Because it is not a number. Put it in as it is. else new_right = statement.right.clone end if (mode == :par && self.mode == :seq) then # Dock the existing left hand side and the replaced right hand side to create a new expression. # Record the expression after conversion to hash to continue seq-> par. new_statement = Transmit.new(statement.left.clone,new_right) $fm.fm_seq["#{statement.left.to_verilog}"] = new_right elsif (mode == :seq && self.mode == :par) && (rep) then unless (res_name(statement.left).name.to_s.include? "#") # Search the variable on the left side and give 'to the name. new_signal = att_signal(statement.left,"'") unless (list.include?(new_signal.name.to_s)) then list << new_signal.name.to_s flat.add_inner(new_signal) end new_statement = Transmit.new(search_refname(statement.left,"'"),new_right) $fm.rep[statement.left] = new_statement end else new_statement = Transmit.new(statement.left.clone,new_right) end end # Add the converted statement to flat (because par -> par or seq -> seq will be added until then). if new_statement.is_a?(Transmit) then unless (mode == :par && self.mode == :seq) && (res_name(new_statement.left).name.to_s.include? "'") then flat.add_statement(new_statement.clone) end else flat.add_statement(new_statement.clone) end if (rep) $fm.rep_sharp.each_key do |key| new_smt = Transmit.new(key.clone,$fm.rep_sharp[key].clone) flat.add_statement(new_smt.clone) end $fm.rep_sharp.clear() # Deactivate rep that has become obsolete. end end # Add an expression after paragraph based on rep. # A complement expression like x = x '. $fm.rep.each_key do |key| new_statement = Transmit.new(key.clone,$fm.rep[key].left.clone) flat.add_statement(new_statement.clone) end $fm.rep.clear() # Deactivate rep that has become obsolete. # Since seq -> par is the end, fm_par is deleted. if (mode == :par && self.mode == :seq) then $fm.fm_seq.clear() end # In case of if statement (when rst == false) you can not convert no or else if you delete the contents of fm_seq. # Therefore, in this case restore the backup to restore. # This means that it is necessary to erase fm_seq once obtained in the if statement once. if(rst == false) then $fm.fm_seq.clear() fm_seq_backup.each_key do |key| $fm.fm_seq[key] = fm_seq_backup[key] end end return flat # Return flat finished checking. end
Generates the text of the equivalent hdr text. level
is the hierachical level of the object. header
tells if the header is to generate or not. timed
tells if its a timed block.
# File lib/HDLRuby/hruby_low2hdr.rb, line 475 def to_hdr(level = 0, header = true, timed = false) # The resulting string. res = "" # Generate the header if required. if header then if timed then res << " " * (level*3) << "timed " else res << " " * (level*3) << "#{self.mode} " end unless self.name.empty? then res << ":" << Low2HDR.hdr_decl_name(self.name) << " " end res << "do\n" end level = level + 1 if header # Generate the inners declaration. self.each_inner do |inner| res << " " * (level*3) res << inner.type.to_hdr(level) res << ".inner :" << Low2HDR.hdr_decl_name(inner.name) << "\n" end # Generate the statements. self.each_statement do |stmnt| res << stmnt.to_hdr(level) end # Close the block. if header then res << " " * ((level-1)*3) << "end\n" end # Return the result. return res end
Creates a new high block statement.
# File lib/HDLRuby/hruby_low2high.rb, line 338 def to_high # Create the new block statement. res = HDLRuby::High::Block.new(self.mode,self.name) # Add the statements. self.each_statement { |stmnt| res.add_statement(stmnt.to_high) } return res end
Convert the block to seq.
# File lib/HDLRuby/hruby_low_without_parinseq.rb, line 122 def to_seq! if self.mode == :par then # Need to convert. # First recurse on the sub blocks. self.each_statement(&:to_seq!) # Now replace each left value by a new signal for # differed assingment in seq. differeds = [] self.each_statement do |statement| left = statement.left if statement.is_a?(Transmit) then sig = SignalI.new(HDLRuby.uniq_name,left.type) self.add_inner(sig) diff = RefName.new(left.type,RefThis.new,sig.name) differeds << [left,diff] statement.set_left!(diff) end end # Adds the differed assignments. differeds.each do |left,diff| self.add_statement(Transmit.new(left.clone,diff.clone)) end # Change the mode. self.set_mode!(:seq) end return self end
Moves the declarations to the upper namespace.
# File lib/HDLRuby/hruby_low_without_namespace.rb, line 672 def to_upper_space! # Recurse on the statements. self.each_statement(&:to_upper_space!) # Extract the declares from the statements. decls = self.each_statement.map(&:extract_declares!) # Reinsert the extracted declares to self. decls.flatten.each { |decl| self.add_inner(decl) } end
Converts the system to Verilog
code adding 'spc' spaces at the begining of each line.
# File lib/HDLRuby/hruby_verilog.rb, line 132 def to_verilog(spc = 3) code = "begin" if self.name && !self.name.empty? then vname = name_to_verilog(self.name) code << " : #{vname}" self.properties[:verilog_name] = vname end code << "\n" if block.each_inner.any? # Declaration of "inner" part within "always". block.each_inner do |inner| if HDLRuby::Low::VERILOG_REGS.include?(inner.to_verilog) then # code << " reg" code << "#{" " * (spc+3)}reg" else code << "#{" " * (spc+3)}wire" end # Variable has "base", but if there is width etc, it is not in "base". # It is determined by an if. if inner.type.base? if inner.type.base.base? code << "#{inner.type.base.to_verilog} #{inner.to_verilog} #{inner.type.to_verilog}" else code << "#{inner.type.to_verilog} #{inner.to_verilog}" end else code << " #{inner.type.to_verilog}#{inner.to_verilog}" end if inner.value then # There is an initial value. code << " = #{inner.value.to_verilog}" end code << ";\n" end # Translate the block that finished scheduling. block.each_statement do |statement| # puts "#{statement.to_verilog(spc+3)}" if statement.is_a?(Block) then code << "\n#{" " * (spc+3)}#{statement.to_verilog(spc+3)}" else code << "\n#{statement.to_verilog(spc+3)}" end end # Close the block." code << "\n#{" "*spc}end" return code end
Generates the text of the equivalent HDLRuby::High
code. vars
is the list of variables and level
is the hierachical level of the object.
NOTE: only the statements are generated, the remaining is assumed
to be handled by the upper scope.
# File lib/HDLRuby/hruby_low2vhd.rb, line 1093 def to_vhdl(vars, level = 0) # The resulting string. res = "" # Generate the statements. self.each_statement do |stmnt| res << stmnt.to_vhdl(vars,level) end # Return the result. return res end
Adds a statement
and the begining of the block
NOTE: TimeWait
is not supported unless for TimeBlock
objects.
# File lib/HDLRuby/hruby_low.rb, line 4117 def unshift_statement(statement) unless statement.is_a?(Statement) then raise AnyError, "Invalid class for a statement: #{statement.class}" end if statement.is_a?(TimeWait) then raise AnyError, "Timed statements are not supported in common blocks." end @statements.unshift(statement) # And set its parent. statement.parent = self statement end
Converts a variable to a reference to it.
# File lib/HDLRuby/hruby_low_with_var.rb, line 57 def var2ref(var) return RefName.new(var.type,RefThis.new,var.name) end
Converts a variable name
to the symbol giving the corresponding HDLRuby
reference.
# File lib/HDLRuby/hruby_low_with_var.rb, line 69 def var_name2sym(name) return name[1..-1].to_sym end
Tell if a name is a variable one.
# File lib/HDLRuby/hruby_low_with_var.rb, line 74 def variable_name?(name) name[0] == "%" end
Get access to the variables
# File lib/HDLRuby/hruby_low_with_var.rb, line 130 def variables # Initializes the set of variables if required. @variables ||= {} return @variables end
Converts to a variable-compatible block where upper
is the upper block if any.
NOTE: the result is a new block.
# File lib/HDLRuby/hruby_low_with_var.rb, line 159 def with_var(upper = nil) # puts "with_var for #{self} with upper=#{upper}" # Recurse on the statements. new_stmnts = [] self.each_statement do |stmnt| # Process stmnt if stmnt.respond_to?(:with_var) then # Can be converted stmnt = stmnt.with_var(self) else # Cannot be converted, simply clone. stmnt = stmnt.clone end # Adds the result. new_stmnts << stmnt end # Handle the cases that does not need directly a variable # convertion # Is the block a par? if self.mode == :par then # Yes, creates a new block with the new statements. block = Block.new(self.mode) self.each_inner { |inner| block.add_inner(inner.clone) } new_stmnts.each {|stmnt| block.add_statement(stmnt) } # Is the block within a seq? if upper && upper.mode == :seq then # Yes, converts to seq. # return self.to_seq return block.blocks2seq! end # No, simply return the block. # block = self.clone return block end # The block is a seq, convert it. # Treat the block sym2var = {} # The table of variable by corresponding signal name # Generate and replace the variables new_stmnts.each do |stmnt| unless stmnt.is_a?(Transmit) then # The statement is not a transmission, extract the # variables that correspond to external signals. extract_from_externals!(stmnt,sym2var) else # Other case: transmission, the left value is to convert # to a variable, and the right values are to be updated # with the existing variables. # First convert the left value to the corresponding symbol. sym = stmnt.left.to_sym # puts "sym=#{sym}" var = sym2var[sym] unless var then var = SignalI.new(sym2var_name(sym),stmnt.left.type) sym2var[sym] = var end # Then replace the relevant references by corresponding # variables refs_by_variables!(stmnt,sym2var) end end # puts "sym2var=#{sym2var}" # Declare the variables in the top block. top = self.top_block # puts "top=#{top}" sym2var.each_value do |var| # puts "Adding var=#{var.name}" top.add_inner(var.clone) unless top.each_inner.find {|v| v.eql?(var) } end # Generate the new block. result = self.class.new(self.mode,self.name) # Adds the inner signals of current block. self.each_inner do |inner| result.add_inner(inner.clone) end # Adds the new statements. new_stmnts.each do |stmnt| result.add_statement(stmnt) end # Adds final statements assigning variables back to the orginal # signals. sym2var.each do |sym,var| result.add_statement( Transmit.new(sym.to_hdr.clone,var2ref(var))) end # End of the conversion. return result end