lib/HDLRuby/hruby_rsim.rb in HDLRuby-2.11.5 vs lib/HDLRuby/hruby_rsim.rb in HDLRuby-2.11.7

- old
+ new

@@ -17,10 +17,15 @@ class SystemT # Tell if the simulation is in multithread mode or not. attr_reader :multithread + ## Add untimed objet +obj+ + def add_untimed(obj) + @untimeds << obj + end + ## Add timed behavior +beh+. # Returns the id of the timed behavior. def add_timed_behavior(beh) @timed_behaviors << beh @total_timed_behaviors += 1 @@ -39,25 +44,36 @@ @sig_active << sig end ## Advance the global simulator. def advance - # Display the time - self.show_time + # # Display the time + # self.show_time shown_values = {} # Get the behaviors waiting on activated signals. until @sig_active.empty? do - # # Update the signals. - # @sig_active.each { |sig| sig.c_value = sig.f_value } # puts "sig_active.size=#{@sig_active.size}" + # puts "sig_active=#{@sig_active.map {|sig| sig.fullname}}" # Look for the behavior sensitive to the signals. + # @sig_active.each do |sig| + # sig.each_anyedge { |beh| @sig_exec << beh } + # if (sig.c_value.zero? && !sig.f_value.zero?) then + # # puts "sig.c_value=#{sig.c_value.content}" + # sig.each_posedge { |beh| @sig_exec << beh } + # elsif (!sig.c_value.zero? && sig.f_value.zero?) then + # sig.each_negedge { |beh| @sig_exec << beh } + # end + # end @sig_active.each do |sig| + next if (sig.c_value.eql?(sig.f_value)) + # next if (sig.c_value.to_vstr == sig.f_value.to_vstr) + # puts "sig.c_value: #{sig.c_value.to_vstr}, sig.f_value=#{sig.f_value.to_vstr}" sig.each_anyedge { |beh| @sig_exec << beh } - if (sig.c_value.zero? && !sig.f_value.zero?) then + if (sig.c_value.zero?) then # puts "sig.c_value=#{sig.c_value.content}" sig.each_posedge { |beh| @sig_exec << beh } - elsif (!sig.c_value.zero? && sig.f_value.zero?) then + elsif (!sig.c_value.zero?) then sig.each_negedge { |beh| @sig_exec << beh } end end # Update the signals. @sig_active.each { |sig| sig.c_value = sig.f_value } @@ -79,10 +95,12 @@ @sig_active.uniq! {|sig| sig.object_id } # puts "@sig_active.size=#{@sig_active.size}" # Advance time. @time = (@timed_behaviors.min {|b0,b1| b0.time <=> b1.time }).time end + # Display the time + self.show_time end ## Run the simulation from the current systemT and outputs the resuts # on simout. def sim(simout) @@ -93,10 +111,12 @@ # Initializes the time. @time = 0 # Initializes the time and signals execution buffers. @tim_exec = [] @sig_exec = [] + # Initilize the list of untimed objects. + @untimeds = [] # Initialize the list of currently exisiting timed behavior. @timed_behaviors = [] # Initialize the list of activated signals. @sig_active = [] # Initializes the total number of timed behaviors (currently @@ -105,10 +125,14 @@ # Initilizes the simulation. self.init_sim(self) # Initialize the displayer. self.show_init(simout) + # Initialize the untimed objects. + self.init_untimeds + # puts "End of init_untimed." + # Is there more than one timed behavior. if @total_timed_behaviors <= 1 then # No, no need of multithreading. @multithread = false # Simple execute the block of the behavior. @@ -203,10 +227,21 @@ # Recurse on the signals. self.each_signal { |sig| sig.init_sim(systemT) } # Recure on the scope. self.scope.init_sim(systemT) end + + ## Initialize the untimed objects. + def init_untimeds + @untimeds.each do |obj| + if obj.is_a?(Behavior) then + obj.block.execute(:seq) + else + obj.execute(:seq) + end + end + end ## Initialize run for executing +ruby_block+ def run_init(&ruby_block) @mutex.synchronize(&ruby_block) end @@ -335,10 +370,12 @@ return self.block.execute(mode) end ## Initialize the simulation for system +systemT+. def init_sim(systemT) + # Add the behavior to the list of untimed objects. + systemT.add_untimed(self) # Process the sensitivity list. # Is it a clocked behavior? events = self.each_event.to_a if events.empty? then # No events, this is not a clock behavior. @@ -349,10 +386,11 @@ node.is_a?(RefObject) && !node.leftvalue? && !node.parent.is_a?(RefObject) end.to_a # Keep only one ref per signal. refs.uniq! { |node| node.fullname } + # puts "refs=#{refs.map {|node| node.fullname}}" # Remove the inner signals from the list. self.block.each_inner do |inner| refs.delete_if {|r| r.name == inner.name } end # Generate the event. @@ -514,12 +552,12 @@ def assign(mode,value) # Set the next value. @f_value = value # Set the mode. @mode = mode - # puts "assign #{value.content} (#{value.content.class}) with self.type.width=#{self.type.width} while value.type.width=#{value.type.width}" if self.name.to_s.include?("idx") - # @f_value = value.cast(self.type) # Cast inserted by HDLRuby normally + # puts "assign #{value.content} (#{value.content.class}) with self.type.width=#{self.type.width} while value.type.width=#{value.type.width}" if self.name.to_s.include?("xnor") + @f_value = value.cast(self.type) # Cast not always inserted by HDLRuby normally end ## Assigns +value+ at +index+ (integer or range). def assign_at(mode,value,index) # @f_value = @f_value.assign_at(mode,value,index) @@ -665,22 +703,22 @@ # Describes a case statement. class Case ## Initialize the simulation for system +systemT+. def init_sim(systemT) self.each_when { |wh| wh.init_sim(systemT) } - self.default.init_sim(systemT) + self.default.init_sim(systemT) if self.default end ## Executes the statement. def execute(mode) unless self.each_when.find do |wh| if wh.match.eql?(self.value.execute(mode)) then wh.statement.execute(mode) return end end - self.default.execute(mode) + self.default.execute(mode) if self.default end end end @@ -847,10 +885,12 @@ # Describes a connection. class Connection ## Initialize the simulation for system +systemT+. def init_sim(systemT) + # Add the connection to the list of untimed objets. + systemT.add_untimed(self) # Recurse on the left. self.left.init_sim(systemT) # Process the sensitivity list. # Is it a clocked behavior? events = [] @@ -859,10 +899,12 @@ refs = self.right.each_node_deep.select do |node| node.is_a?(RefObject) && !node.parent.is_a?(RefObject) end.to_a # Keep only one ref per signal. refs.uniq! { |node| node.fullname } + # puts "connection input: #{self.left.fullname}" + # puts "connection refs=#{refs.map {|node| node.fullname}}" # # Generate the event. # events = refs.map {|ref| Event.new(:anyedge,ref) } # # Add them to the behavior for further processing. # events.each {|event| self.add_event(event) } # Now process the events: add the connection to the corresponding @@ -870,11 +912,11 @@ refs.each {|ref| ref.object.add_anyedge(self) } end ## Executes the statement. def execute(mode) - # puts "connection = #{self}" + # puts "connection = #{self}" if self.left.is_a?(RefObject) && self.left.object.name.to_s.include?("xnor") self.left.assign(mode,self.right.execute(mode)) end end @@ -970,13 +1012,21 @@ # # NOTE: choice is using the value of +select+ as an index. class Select ## Execute the expression. def execute(mode) + unless @mask then + # Need to initialize the execution of the select. + width = (@choices.size-1).width + width = 1 if width == 0 + @mask = 2**width - 1 + @choices.concat([@choices[-1]] * (2**width-@choices.size)) + end # Recurse on the select. - tmps = self.select.execute(mode) + tmps = self.select.execute(mode).to_i & @mask + # puts "select tmps=#{tmps}, @choices.size=#{@choices.size}" # Recurse on the selection result. - return @choices[tmps.to_i].execute(mode) + return @choices[tmps].execute(mode) end end ##