stumped

J

Jeff Patterson

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 helpful 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[:D])
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 helps, 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
 
J

Joel VanderWerf

Jeff said:
#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.)
 
J

Joel VanderWerf

Joel said:
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
 
J

Jeff Patterson

Joel said:
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 help!

Jeff
 
J

Jeff Patterson

Jeff said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top