Gate class working
This commit is contained in:
parent
6f3db5ae4c
commit
c0b1776d20
43
gate.rb
43
gate.rb
@ -1,6 +1,47 @@
|
||||
require_relative "port.rb"
|
||||
|
||||
# @abstract Subclass and override {#input_changed} to implement a gate
|
||||
# @abstract Subclass and override {#inputs_changed} to implement a gate
|
||||
## Base class for gates
|
||||
class Gate
|
||||
|
||||
# @!attribute [r] out
|
||||
# @return [Port] the output port of the gate
|
||||
attr_reader :out
|
||||
|
||||
# @param args [Array<Port>] These are the ports to be added to the gate.
|
||||
# @note The first argument determines the width of the gate.
|
||||
def initialize(*args)
|
||||
@inputs=[]
|
||||
@width=args[0].width
|
||||
@out=Port.new(@width)
|
||||
args.each do |input|
|
||||
add_input(input)
|
||||
end
|
||||
end
|
||||
|
||||
# Add a port to the gate.
|
||||
# @param port [Port] The port to be added. It must match the width of the gate.
|
||||
# @return [void]
|
||||
def add_input(port)
|
||||
if port.width != @width then
|
||||
raise ArgumentError, "Incorrect width #{port.width}, expected #{@width}"
|
||||
end
|
||||
@inputs.push(port)
|
||||
port.add_callback do |value|
|
||||
vals=[]
|
||||
@inputs.each do |port|
|
||||
vals.push port.val
|
||||
end
|
||||
inputs_changed(vals)
|
||||
end
|
||||
vals=[]
|
||||
@inputs.each do |port|
|
||||
vals.push port.val
|
||||
end
|
||||
inputs_changed(vals)
|
||||
end
|
||||
|
||||
# @abstract Override this to implement a gate.
|
||||
# @param vals [Array<Integer>] List of values for connected ports.
|
||||
def inputs_changed(vals); raise NotImplementedError; end
|
||||
end
|
||||
|
17
port.rb
17
port.rb
@ -19,6 +19,7 @@ class Port
|
||||
# @param name [String] The name of the port
|
||||
def initialize(width, name="")
|
||||
@connected=[]
|
||||
@callbacks=[]
|
||||
@propagating=false
|
||||
@val=0
|
||||
@width=width
|
||||
@ -26,8 +27,9 @@ class Port
|
||||
@strname=name
|
||||
end
|
||||
|
||||
# Sets the port's value
|
||||
# @param val [Integer] The new value for the port
|
||||
# Sets the port's value and calls all registered callbacks
|
||||
# @param val [Integer] The new value for the port.
|
||||
# It must not exceed (width^2)-1,or an ArgumentError will be raised.
|
||||
# @return [void]
|
||||
def setval(val)
|
||||
# Prevent infinite loops when the connected port calls back when propagating.
|
||||
@ -37,6 +39,9 @@ class Port
|
||||
else
|
||||
raise ArgumentError,"#{val} is over maximum of #{@maxval}"
|
||||
end
|
||||
@callbacks.each do |callback|
|
||||
callback.call(@val)
|
||||
end
|
||||
@propagating=true
|
||||
propagate()
|
||||
@propagating=false
|
||||
@ -51,6 +56,14 @@ class Port
|
||||
port.connect_back(self)
|
||||
end
|
||||
|
||||
# Adds a callback.
|
||||
# @yield When callback called, gives the value of the port.
|
||||
# @yieldparam value [Integer] The value of the port.
|
||||
def add_callback(&callback)
|
||||
#add block to the list, put at head
|
||||
@callbacks.insert(0, callback)
|
||||
end
|
||||
|
||||
# Returns a string representation for debugging
|
||||
# @return [String] String name of the port, or super if none
|
||||
def to_s()
|
||||
|
34
spec/gate_spec.rb
Normal file
34
spec/gate_spec.rb
Normal file
@ -0,0 +1,34 @@
|
||||
require_relative "../gate.rb"
|
||||
require_relative "../port.rb"
|
||||
|
||||
describe Gate do
|
||||
let(:klass) do
|
||||
Class.new(Gate) do
|
||||
def inputs_changed(vals)
|
||||
tot=0
|
||||
vals.each do |val|
|
||||
tot+=val
|
||||
end
|
||||
out.setval(tot)
|
||||
end
|
||||
end
|
||||
end
|
||||
it "calls #inputs_changed when input values change or an input is added" do
|
||||
a=Port.new(8)
|
||||
b=Port.new(8)
|
||||
gate=klass.new(a,b)
|
||||
expect(gate).to receive(:inputs_changed).with([8,0])
|
||||
a.setval(8)
|
||||
expect(gate).to receive(:inputs_changed).with([8,10])
|
||||
b.setval(10)
|
||||
end
|
||||
|
||||
it "can perform computations in #inputs_changed" do
|
||||
a=Port.new(8)
|
||||
b=Port.new(8)
|
||||
gate=klass.new(a,b)
|
||||
a.setval(8)
|
||||
b.setval(10)
|
||||
expect(gate.out.val).to eq(18)
|
||||
end
|
||||
end
|
@ -1,13 +1,13 @@
|
||||
require_relative "../port.rb"
|
||||
|
||||
describe Port do
|
||||
it "should set the port's value when we call setval" do
|
||||
it "should set the port's value when we call #setval" do
|
||||
a=Port.new(4)
|
||||
a.setval(1)
|
||||
expect(a).to eq 1
|
||||
end
|
||||
|
||||
it "should propagate values when we call setval" do
|
||||
it "should propagate values when we call #setval" do
|
||||
a=Port.new(4)
|
||||
b=Port.new(4)
|
||||
c=Port.new(4)
|
||||
@ -42,4 +42,10 @@ describe Port do
|
||||
a=Port.new(4)
|
||||
expect {a.setval(16)}.to raise_error ArgumentError
|
||||
end
|
||||
|
||||
it "should call registered callbacks" do
|
||||
a=Port.new(4)
|
||||
expect { |b| a.add_callback(&b); a.setval(10) }.to yield_with_args(10)
|
||||
expect { |b| a.add_callback(&b); a.setval(8) }.to yield_with_args(8)
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user