class Object
Constants
- Ms
XLs = [ $x0l, $x1l, $x2l, $x3l, $x4l, $x5l, $x6l ]
- NNs
NLs = [ $n0l, $n1l, $n2l, $n3l, $n4l, $n5l ]
- Ns
The various combinations of bit strings to test.
- S
- STRs
MLs = [ $m0l, $m1l, $m2l, $m3l, $m4l, $m5l, $m6l, $m7l ]
- Xs
ZLs = [ $z0l, $z1l, $z2l, $z3l, $z4l, $z5l, $z6l ]
- Zs
Public Class Methods
Tells HDLRuby
has finised booting.
# File lib/HDLRuby/hruby_high.rb, line 4800 def self.booting? false end
Enters in HDLRuby::High
mode.
# File lib/HDLRuby/hruby_high.rb, line 4762 def self.configure_high if $HDLRuby_configure then # Already configured. return end # Now HDLRuby will be configured. $HDLRuby_configure = true include HDLRuby::High class << self # For main, missing methods are looked for in the namespaces. def method_missing(m, *args, &ruby_block) # print "method_missing in class=#{self.class} with m=#{m}\n" # Is the missing method an immediate value? value = m.to_value return value if value and args.empty? # puts "Universe methods: #{Universe.namespace.methods}" # Not a value, but maybe it is in the namespaces if Namespaces[-1].respond_to?(m) then # Yes use it. Namespaces[-1].send(m,*args,&ruby_block) else # puts "here: #{m}" # No, true error raise NotDefinedError, "undefined HDLRuby construct, local variable or method `#{m}'." end end end # Initialize the this. set_this # Generate the standard signals $clk = Universe.scope.inner :__universe__clk__ $rst = Universe.scope.inner :__universe__rst__ # Tells HDLRuby has finised booting. def self.booting? false end end
For main, missing methods are looked for in the namespaces.
# File lib/HDLRuby/hruby_high.rb, line 4772 def method_missing(m, *args, &ruby_block) # print "method_missing in class=#{self.class} with m=#{m}\n" # Is the missing method an immediate value? value = m.to_value return value if value and args.empty? # puts "Universe methods: #{Universe.namespace.methods}" # Not a value, but maybe it is in the namespaces if Namespaces[-1].respond_to?(m) then # Yes use it. Namespaces[-1].send(m,*args,&ruby_block) else # puts "here: #{m}" # No, true error raise NotDefinedError, "undefined HDLRuby construct, local variable or method `#{m}'." end end
Public Instance Methods
# File lib/HDLRuby/high_samples/paper_after.rb, line 5 def after(number, clk = $clk, rst = $rst, &code) if in_behavior? and cur_behavior.on_edge? then counter = HDLRuby.uniq_name counter = [Math::log2(number).to_i+1].inner counter hif(rst) { counter <= 0 } helsif(counter < number) do counter <= counter + 1 end # hif(counter >= number) { code.call } hif(counter >= number) { instance_eval(&code) } else counter = HDLRuby.uniq_name cur_system.open do counter = [Math::log2(number).to_i+1].inner counter par(clk.posedge,rst.posedge) do hif(rst) { counter <= 0 } helse { counter <= counter + 1 } end end # hif(counter >= number) { code.call } hif(counter >= number) { instance_eval(&code) } end end
# File lib/HDLRuby/hdr_samples/calculator.rb, line 15 def common s <= tmp[7..0] zf <= (s == 0) sf <= tmp[7] cf <= tmp[8] vf <= tmp[8] ^ tmp[7] goto(:choice) end
# File lib/HDLRuby/hdr_samples/with_to_array.rb, line 2 def connect8(i0,i1,i2,i3,i4,i5,i6,i7, o0,o1,o2,o3,o4,o5,o6,o7) o0 <= i0 o1 <= i1 o2 <= i2 o3 <= i3 o4 <= i4 o5 <= i5 o6 <= i6 o7 <= i7 end
Generate an expression from a signal or constant name
# File lib/HDLRuby/test_hruby_low.rb, line 258 def eName2Exp(name) # puts "eName2Exp with name=#{name}" ref = $refs.find do |ref| if ref.ref.respond_to?(:name) then ref.ref.name == name.to_sym else ref.name == name.to_sym end end # puts "ref=#{ref}" unless ref return Value.new($bit8,name.to_i) end return ref end
Module Generating a foward propagation structure of a NN. Params:
-
typ
: the data type for standard computations. -
arch
: the architecture of the NN as a array of columns sizes -
samps
: the NN input and expected outputs samples as a 3D array -
b_init
:the bias initial values as a 2D array -
w_init
:the weights initial values as a 3D array -
actP
: the activation proc, default: ReLU -
sopP
: the sum of production function, default: basic operators
# File lib/HDLRuby/hdr_samples/neural/forward.rb, line 19 system :forward do |typ,arch,samps,b_init,w_init, actP = proc { |z| mux(z < 0, 0, z) }, sopP = proc do |xs,ws| xs.zip(ws).map{ |x,w| x*w }.reduce(:+) end | ### # The interface signals # The control signals input :clk, :reset input :din, :select_initial # The input signals for updating of the weights and biases, # and the output signals giving the corresponding current values. cap_bs = [] bs = [] cap_ws = [] ws = [] arch[1..-1].each.with_index do |col,i| cap_bs << [] bs << [] # The biase update inputs and value outputs col.times do |j| cap_bs[-1] << ( typ.input :"cap_b#{i+1}_#{j+1}" ) bs[-1] << ( typ.output :"b#{i+1}_#{j+1}" ) end # The weigh update inputs and value outputs cap_ws << [] ws << [] col.times do |j0| cap_ws[-1] << [] ws[-1] << [] arch[i].times do |j1| cap_ws[-1][-1] << ( typ.input :"cap_w#{i+1}_#{j0+1}#{j1+1}" ) ws[-1][-1] << ( typ.output :"w#{i+1}_#{j0+1}#{j1+1}" ) end end end # The output signals giving each neuron output. as = [] arch[1..-1].each.with_index do |col,i| as << [] col.times do |j| as[-1] << ( typ.output :"a#{i+1}_#{j+1}" ) end end # The output signals indicating the current NN input and expected # answer (they are provided by an inner memory). ks = [] arch[0].times do |i| # NN input ks << ( typ.output :"k#{i+1}" ) end ts = [] arch[-1].times do |i| # NN expected answer ts << ( typ.output :"t#{i+1}" ) end ### # The inner signals # The control signals inner :select_update typedef(:outT) { [Math::log2(samps[0][0].size).ceil] } # Sample counter type outT.inner :out # The neurons sum results. zs = [] arch[1..-1].each.with_index do |col,i| zs << [] col.times do |j| zs[-1] << ( typ.inner :"z#{i+1}_#{j+1}" ) end end ### # The structural description (instantiation of thre neuron computation # systems) # Sample counter counter(outT,samps[0][0].size).(:counterI).(clk, reset, out) # Neuron update selector, the skip size is (NN depth)*4+1 # (4-cycle neurons and one addition sync cycle). selector(arch.size*4+1).(:selectorI).(clk, reset, select_update) # Input and expected output memories arch[0].times do |i| # Samples for input i mem(typ,outT,samps[0][i]).(:"k#{i+1}I").(clk, din, out, ks[i]) end arch[-1].times do |i| # Expected values for output i mem(typ,outT,samps[1][i]).(:"t#{i+1}I").(clk, din, out, ts[i]) end # Biases and weights arch[1..-1].each.with_index do |col,i| # Biases col.times do |j| bw(typ,b_init[i][j]). (:"b#{i+1}_#{j+1}I").(clk, reset, cap_bs[i][j], select_initial, select_update, bs[i][j]) end # Weights col.times do |j0| arch[i].times do |j1| bw(typ,w_init[i][j0][j1]). (:"w#{i+1}_#{j0+1}#{j1+1}I").(clk,reset,cap_ws[i][j0][j1], select_initial, select_update, ws[i][j0][j1]) end end end # Weighted Sums # First column arch[1].times do |j| z(typ,ks.size,sopP).(:"z2_#{j+1}I"). (clk, reset, *ks, *ws[0][j], bs[0][j], zs[0][j]) end # Other columns arch[2..-1].each.with_index do |col,i| col.times do |j| z(typ,as[i].size,sopP).(:"z#{i+3}_#{j+1}I"). (clk, reset, *as[i], *ws[i+1][j], bs[i+1][j], zs[i+1][j]) end end # Activations arch[1..-1].each.with_index do |col,i| col.times do |j| a(typ,actP).(:"a#{i+1}_#{j+1}I").(clk, reset, zs[i][j], as[i][j]) end end end
A fully specified forward module with 8.24-bit fixed point computation and 4.4bit table-based sigmoid activation function. Structure: 2 inputs, one 3-column hidden layer and 2 outputs.
# File lib/HDLRuby/hdr_samples/neural/forward_sub.rb, line 9 system :forward_sub, forward( signed[31..0], # Data type [2,3,2], # NN structure [ # Input samples. # First input. [[_sh08000000, _sh08000000, _sh05000000, _sh05000000, *([_sh00000000]*28)], # Second input. [_sh08000000, _sh05000000, _sh08000000, _sh05000000, *([_sh00000000]*28)]], # Expected outputs # First output [[_sh01000000, _sh00000000, _sh00000000, _sh00000000, *([_sh00000000]*28)], # Second output [_sh00000000, _sh01000000, _sh01000000, _sh01000000, *([_sh00000000]*28)]]
# File lib/HDLRuby/test_hruby_high.rb, line 536 def hello(name) $hello = "Hello #{name}." end
# File lib/HDLRuby/high_samples/functions.rb, line 31 def hello_in puts "hello_in" a <= x + y end
# File lib/HDLRuby/high_samples/functions.rb, line 10 def hello_mix(u,v,w) puts "hello_mix" par do inner :something w <= u - v end end
# File lib/HDLRuby/high_samples/functions.rb, line 6 def hello_out puts "hello_out" end
Function generating a register declaration.
# File lib/HDLRuby/high_samples/registers.rb, line 123 def make_reg(name,&blk) system name do |*arg| input :clk, :rst blk.(*arg).input :d blk.(*arg).output :q,:qb qb <= ~q (q <= d & [~rst]*blk.(*arg).width).at(clk.posedge) end end
Function generating the body of a register description.
# File lib/HDLRuby/high_samples/registers.rb, line 87 def make_reg_body(typ) input :clk, :rst typ.input :d typ.output :q,:qb qb <= ~q (q <= d & [~rst]*typ.width).at(clk.posedge) end
Generates a N-dimension array described by geometry
filled with width
bit values.
# File lib/HDLRuby/hdr_samples/neural/random.rb, line 8 def rand_array(geometry,width) if geometry.is_a?(Array) then # Geometry is hierarchical, recurse on it. return geometry.map {|elem| rand_array(elem,width) } else # Geometry is a size of a 1-D array, generate it. return geometry.times.map { |i| rand_signed(width) } end end
Generate a width
bit (signed) random value.
# File lib/HDLRuby/hdr_samples/neural/random.rb, line 2 def rand_signed(width) :"_s#{width.times.map { Random.rand(0..1).to_s }.join }".to_expr end
# File lib/HDLRuby/hdr_samples/neural/sigmoid.rb, line 1 def sigmoid(a_width, a_point, d_width, d_point, addr) # Initialize the result to force it as a ruby variable. High.cur_system.open do sub do # Generates the rom [d_width][2**a_width].inner :contents contents <= (2**a_width).times.map do |i| # Converts i to a float i = i.to_f * 2**(-a_point) # Compute the sigmoid sigm = (1.0 / (1+Math.exp(i))) # Convert it to fixed point (sigm * 2**d_point).to_i end # Use it for the access contents[addr[(a_point+d_width-1-d_point)..a_point-d_point]] end end end
Loop num
times executing ruby_block
. The loop is synchronized on clk_e
.
# File lib/HDLRuby/std/loop.rb, line 91 def times_loop(clk_e, num, &ruby_block) # Compute the width of the counter. width = num.respond_to?(:width) ? num.width : num.type.width # Declares the counter. cnt = [width].inner(HDLRuby.uniq_name) # Create the loop. return while_loop(clk_e, proc{cnt<=0}, cnt<num) do cnt <= cnt + 1 ruby_block.call end end
Locate an executable from cmd.
# File lib/HDLRuby/hdrcc.rb, line 256 def which(cmd) # Get the possible exetensions (for windows case). exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] # Look for the command within the executable paths. ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| exts.each do |ext| exe = File.join(path, "#{cmd}#{ext}") return exe if File.executable?(exe) && !File.directory?(exe) end end nil end
A simplified loop: loops until condition
is met execution ruby_block
. The loop is synchronized on clk_e
and initialized by init
. If condition
is nil, then init
is used as condition
.
# File lib/HDLRuby/std/loop.rb, line 80 def while_loop(clk_e, init, condition = nil, &ruby_block) # Create the loop task. tsk = while_task(clk_e,init,condition,ruby_block).(HDLRuby.uniq_name) # Create the inner access port. prt = tsk.inner HDLRuby.uniq_name # Return the access port. return prt end
Generates a xcd file from the HDLRuby
objects from top
using their 'xcd' properties. The file is saved in path
directory.
# File lib/HDLRuby/drivers/xcd.rb, line 11 def xcd_generator(top, path) # Ensure top is a system. if top.is_a?(HDLRuby::Low::SystemI) then top = top.systemT elsif !top.is_a?(HDLRuby::Low::SystemT) then raise "The 'xcd_generator' driver can only be applied on SystemT objects." end # Get the name of the resulting file if any. if (top.properties.key?(:xcd_file)) then xcd_file = top.properties[:xcd_file].join else # Default file name. xcd_file = "default.xcd" end # Get the target template. xcd_target = top.properties[:xcd_target].join xcd_target_name = xcd_target xcd_target_name += ".xcd" unless xcd_target_name.end_with?(".xcd") xcd_target_tries = [ xcd_target_name, File.join(path,xcd_target_name), File.join(File.dirname(__FILE__),"xcd",xcd_target_name) ] xcd_target_file = xcd_target_tries.find { |fname| File.exist?(fname) } unless xcd_target_file then raise "XCD target template not found for #{xcd_target}." end # Load the template. template = File.read(xcd_target_file) # Gather the signals by xcd key. xcd2sig = top.each_signal.reduce([]) do |ar,sig| ar += sig.properties.each_with_key(:xcd).map do |val| [val,sig.name.to_s] end end # Create the template expander that will generate the xcd file. expander = TemplateExpander.new([ [ /^\?.*(\n|\z)/, proc do |str| # Signal link to port if xcd2sig.any? do |match,rep| if str.include?(match) then str = str.gsub("<>",rep)[1..-1] else false end end then str else "" end end ] ]) # # Generate the xcd file. # File.open(File.join(path,xcd_file),"w") do |file| # # Generate the signals mapping. # top.each_signal do |signal| # signal.properties.each_with_key(:xcd) do |value| # file << "#{value}\n" # end # end # end # Generate the xcd file. File.open(File.join(path,xcd_file),"w") do |file| expander.expand(template,file) end end