|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
I'm learning ruby by writing a hardware simulator. Since the users will
be first year EE majors with no software skills, it is important that the syntax they will use to describe circuits be as clean and intuitive as possible. With some ful hints obtained in an earlier post on this forum, I've got the netlist description down to this ================= class Top < NetList def initialize(name);super #instantiate the blocks create 'Nco', NCO create 'clk', Clk create 'fifo1',ShiftReg,4 #provide a control interface create 'nCnfg', CtrlInfc, { # :field =>length (lsb -> msb) :AngMod => 1, :AngModTyp => 1, :AngModScl => 5, :PhsRnd => 1, :AmpRnd => 1, :SpurElim => 1, :SwpTyp => 1, :Swp => 1, :BbSrc => 1, :MrkSrc => 1, :PnPolySel => 1 } #wire 'em up @clk.bind(@Nco[:Clk_in]) @clk.bind(@fifo1[:Clk]) @nCnfg[:ANGMOD].bind(@Nco[:freq]) @nCnfg[:BV].bind(@fifo1[ ])end #read control cmds from stdin #run method inherited from Netlist super class def run() cmd='' print "ready>" while((cmd=gets) !~ /^\.$/) begin eval cmd,binding() rescue Exception=>e puts e.message end print "ready>" end end end sim=Simulation.new(Top.new("DDS")) sim.run() ======================= The simulation can be controlled either interactively or from a file that might look like: @Nco[:Rst].set(true) @nCnfg[:bv]=0 yield 1 @Nco[:Rst].set(false) @nCnfg[:AngMod]=1 yield 10 @nCnfg.set(:AngMod =>0.01,:ModType =>0) yield 10 these command are read in the run method above which pass them to eval to set certain nodes in the simulation to certain values. A yield command advances the simulation by yielding to the simulator's run method which advances the indicated number of steps. So far so good. But eval seems to barf if I give it more than one command per line. I.e. what I want to be able to do pass in a command something like 10.times{ some_node.set(some_value);yield 1;n+=1} and have it work as expected. Instead the eval gives /systemR.rb:24: warning: multiple values for a block parameter (0 for 1) and the simulation does not advance. In case it s, here's the simulators run method that is being yielded to: @sim.run{|cyc| while (cyc>0) puts "\n#@cycles" #update the system clocks-causes scheduled clock outputs to update @clks.each{|x| x.update} #update asynchronous elements-causes their listners to schedule an update @elements.each{|x| x.update} #empty the scheduler queue @elements=[] @cycles += 1 cyc -= 1 end } end I think the basic problem boils down to this: I need the method and block to cooperate like block statement #1 block block statement #1 block block yield <---- method returns here block block end block statement #2 block yield <----- method returns here when blocks are nested Any ideas? Thanks in advance Jeff -- Posted via http://www.ruby-forum.com/. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Jeff Patterson wrote:
> #run method inherited from Netlist super class > def run() > cmd='' > print "ready>" > while((cmd=gets) !~ /^\.$/) > begin > eval cmd,binding() > rescue Exception=>e > puts e.message > end > print "ready>" > end > end > end One suggestion: use readline. It's more user friendly. A minimal example is: require "readline" while line=Readline.readline("> ", true) puts line end The above, though simple, has cmdline history and editing. For command completion, you can do something like this: require "readline" require "abbrev" commands = %w{foo bar baz quux} abbrevs = commands.abbrev Readline.completion_proc = proc {|str| abbrevs[str]} puts "Commands are #{commands.join(" ")}. Use ^D to quit." while line=Readline.readline("> ", true) puts line end (But note that this doesn't handle the "bar"/"baz" amibiguity. The completion proc would have to be smarter for that.) -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407 |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
Joel VanderWerf wrote:
> Jeff Patterson wrote: >> #run method inherited from Netlist super class >> def run() >> cmd='' >> print "ready>" >> while((cmd=gets) !~ /^\.$/) >> begin >> eval cmd,binding() >> rescue Exception=>e >> puts e.message >> end >> print "ready>" >> end >> end >> end > > One suggestion: use readline. It's more user friendly. On second thought, since you're evaling the input, you might want to hook your simulation engine up to irb. This uses readline, too, but has the advantage of maintaining program state between lines, so that you can define local vars, methods, etc. Also, it accepts multiline inputs. This is the snippet I start from when I want to do that: require 'irb' require 'irb/completion' module IRB def IRB.parse_opts # Don't touch ARGV, which belongs to the app which called this module. end def IRB.start_session(*args) unless $irb IRB.setup nil ## maybe set some opts here, as in parse_opts in irb/init.rb? end workspace = WorkSpace.new(*args) if @CONF[:SCRIPT] ## normally, set by parse_opts $irb = Irb.new(workspace, @CONF[:SCRIPT]) else $irb = Irb.new(workspace) end @CONF[:IRB_RC].call($irb.context) if @CONF[:IRB_RC] @CONF[:MAIN_CONTEXT] = $irb.context trap 'INT' do $irb.signal_handle end custom_configuration if defined?(IRB.custom_configuration) catch :IRB_EXIT do $irb.eval_input end ## might want to reset your app's interrupt handler here end end class Object include IRB::ExtendCommandBundle # so that Marshal.dump works end if __FILE__ == $0 x = Object.new puts "\nStarted irb shell for x" IRB.start_session(x) puts "\nStarted irb shell for x with current binding" IRB.start_session(binding, x) puts "\nRestarted irb shell for x with current binding" $irb.eval_input puts "\nExited irb shell" p x end -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407 |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
Joel VanderWerf wrote:
> Joel VanderWerf wrote: > > On second thought, since you're evaling the input, you might want to > hook your simulation engine up to irb. This uses readline, too, but has > the advantage of maintaining program state between lines, so that you > can define local vars, methods, etc. Also, it accepts multiline inputs. > Thanks for your suggestions. I tried the irb approach and while command history is very nice. The error I am (still) getting turns out to stem from the fact that in the loop I was trying to execute, I said "yield" instead of "yield 1". Is there a way to default a parameter passed to a block the same way you can default arguments passed to a method? i.e if @sim is my netlist whose run method reads in the commands, I want to do something like @sim.run{|cyc =1| # ERROR while (cyc>0) ...advance the simulator cyc cycles end } I tried @sim.run{|cyc| cyc ||= 1 ... which keeps the program from bombing but I still get the warning Thanks for your ! Jeff -- Posted via http://www.ruby-forum.com/. |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
Jeff Patterson wrote:
> > I tried > @sim.run{|cyc| > cyc ||= 1 > ... > > which keeps the program from bombing but I still get the warning > @sim.run{|*c| cyc=c[0] || 1 works but seems a little klunky. -- Posted via http://www.ruby-forum.com/. |
|
![]() |
| Outils de la discussion | |
|
|