I suspect that the set that contains Ruby Programmers AND HDL coders is 
pretty small (maybe it only contains me at this point), so this may not 
make much sense to the vast majority of Rubyists out there.

I'm probably jumping the gun a bit by announcing this, but It's just 
amazing how much progress I've made on this in only a couple of days - it 
just goes to show the power of Ruby.

Anyway, I've had an idea for a while now for creating a Hardware 
Description Language using Ruby.  It's been done with Java (JHDL - see:
http://www.jhdl.org/ ) and also in Perl (see the Hardware::Simulator 
module on CPAN) so I wanted to try it in Ruby.

For those not familiar with HDLs they are languages used to describe 
hardware designs, kind of similar to textual schematics, but much more 
powerful because they are programming languages.  HDL's tend to look very 
different from regular programming languages, however.  A lot of stuff has 
to appear to happen in parallel in an HDL.

I tried to make RHDL look very similar to VHDL, a widely used HDL in 
industry (the other being Verilog).  Here's an example of a design that 
has a couple of inputs and produces outputs based on OR'ing, AND'ing and 
inverting inputs.  It also contains a process which is sensitive to a clk 
signal and increments a counter whenever 'clk' changes and is equal to 
'1':

#################<<<RHDL>>>######################

class My_Design < RHDL::Design
include RHDL
  def initialize()
    inputs  = { 'A' => Port.new(),
                'B' => Port.new()  }
    outputs = { 'NOT_A' => Port.new(),
		'A_OR_B' => Port.new(),
		'CLK' => Port.new(),
		'A_AND_B' => Port.new()
	      }
    super(inputs,outputs)
    #define internal signals
    a = Signal.new(Bit.new('1')); inputs['A'].connect(a)
    b = Signal.new(Bit.new('0')); inputs['B'].connect(b)
    o = Signal.new(Bit.new());    outputs['NOT_A'].connect(o)
    o2= Signal.new(Bit.new());    outputs['A_AND_B'].connect(o2)
    o3= Signal.new(Bit.new());    outputs['A_OR_B'].connect(o3)
    clk= Signal.new(Bit.new('0'));    outputs['CLK'].connect(clk)
    counter = 0
    define_behavior { 

                      o2<= proc{a * b} 
                      o3<= proc{a + b} 
         	       o<= proc{ a.inv }
                      #create a clock that changes every 2 cycles:
		      clk.assign_at(proc{ clk.inv },2 )
		      process(clk) {
			if clk == '1' && clk.event 
			  counter += 1
			  puts "counter = #{counter}"
			end
		      }

		    }
  end
end

bit_values = ['0','1','Z','X']

#now instantiate the design and step through it while assigning all 
#possible values to A and B inputs:
md = My_Design.new()
bit_values.each { |v|
    bit_values.each { |v2|
       md.step({'A' => v,'B' => v2 })
     }
}

################>>>RHDL<<<###################

And here's the output from running this design:

Inputs: A = 0 B = 0  Outputs: CLK = 0 NOT_A = 1 A_OR_B = 0 A_AND_B = 0 
Inputs: A = 0 B = 1  Outputs: CLK = 1 NOT_A = 1 A_OR_B = 1 A_AND_B = 0 
counter = 1
Inputs: A = 0 B = Z  Outputs: CLK = 1 NOT_A = 1 A_OR_B = X A_AND_B = X 
Inputs: A = 0 B = X  Outputs: CLK = 0 NOT_A = 1 A_OR_B = X A_AND_B = X 
Inputs: A = 1 B = 0  Outputs: CLK = 0 NOT_A = 0 A_OR_B = 1 A_AND_B = 0 
Inputs: A = 1 B = 1  Outputs: CLK = 1 NOT_A = 0 A_OR_B = 1 A_AND_B = 1 
counter = 2
Inputs: A = 1 B = Z  Outputs: CLK = 1 NOT_A = 0 A_OR_B = X A_AND_B = X 
Inputs: A = 1 B = X  Outputs: CLK = 0 NOT_A = 0 A_OR_B = X A_AND_B = X 
Inputs: A = Z B = 0  Outputs: CLK = 0 NOT_A = X A_OR_B = X A_AND_B = X 
Inputs: A = Z B = 1  Outputs: CLK = 1 NOT_A = X A_OR_B = X A_AND_B = X 
counter = 3
Inputs: A = Z B = Z  Outputs: CLK = 1 NOT_A = X A_OR_B = X A_AND_B = X 
Inputs: A = Z B = X  Outputs: CLK = 0 NOT_A = X A_OR_B = X A_AND_B = X 
Inputs: A = X B = 0  Outputs: CLK = 0 NOT_A = X A_OR_B = X A_AND_B = X 
Inputs: A = X B = 1  Outputs: CLK = 1 NOT_A = X A_OR_B = X A_AND_B = X 
counter = 4
Inputs: A = X B = Z  Outputs: CLK = 1 NOT_A = X A_OR_B = X A_AND_B = X 
Inputs: A = X B = X  Outputs: CLK = 0 NOT_A = X A_OR_B = X A_AND_B = X 

The amazing thing is that the module RHDL is only 300 lines of Ruby!
And, I think it has some advantages over JHDL which seems to only allow a 
structural style at this point (ie. in JHDL you have to instanitate 
primitive gates, it doesn't seem to allow equations).

This is mostly a proof of concept, so for now if you're interested in 
getting the RHDL source code send me an email. 

TODO:
* code cleanup - Like I said, I did this in a couple of days and the code 
tends to show it ;-)
* get rid of the need for 'proc's for equation assignments (I think it's 
doable, so they'll look like: o <= {a+b}  but I also want to allow:
o <= a [the case where there is no equation] )
* define a Bit_Vector class so signals can have width (as in busses).
* I'll probably change the operators to AND, OR, XOR so that *,+,^ can 
have their normal uses (and it's consistent with VHDL).
* Way in the future: look at a way to generate VHDL from RHDL.

Phil