Gate class working

This commit is contained in:
pjht 2018-07-09 14:56:30 -05:00
parent 6f3db5ae4c
commit c0b1776d20
4 changed files with 99 additions and 5 deletions

43
gate.rb
View File

@ -1,6 +1,47 @@
require_relative "port.rb" 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 ## Base class for gates
class Gate 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 end

17
port.rb
View File

@ -19,6 +19,7 @@ class Port
# @param name [String] The name of the port # @param name [String] The name of the port
def initialize(width, name="") def initialize(width, name="")
@connected=[] @connected=[]
@callbacks=[]
@propagating=false @propagating=false
@val=0 @val=0
@width=width @width=width
@ -26,8 +27,9 @@ class Port
@strname=name @strname=name
end end
# Sets the port's value # Sets the port's value and calls all registered callbacks
# @param val [Integer] The new value for the port # @param val [Integer] The new value for the port.
# It must not exceed (width^2)-1,or an ArgumentError will be raised.
# @return [void] # @return [void]
def setval(val) def setval(val)
# Prevent infinite loops when the connected port calls back when propagating. # Prevent infinite loops when the connected port calls back when propagating.
@ -37,6 +39,9 @@ class Port
else else
raise ArgumentError,"#{val} is over maximum of #{@maxval}" raise ArgumentError,"#{val} is over maximum of #{@maxval}"
end end
@callbacks.each do |callback|
callback.call(@val)
end
@propagating=true @propagating=true
propagate() propagate()
@propagating=false @propagating=false
@ -51,6 +56,14 @@ class Port
port.connect_back(self) port.connect_back(self)
end 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 # Returns a string representation for debugging
# @return [String] String name of the port, or super if none # @return [String] String name of the port, or super if none
def to_s() def to_s()

34
spec/gate_spec.rb Normal file
View 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

View File

@ -1,13 +1,13 @@
require_relative "../port.rb" require_relative "../port.rb"
describe Port do 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=Port.new(4)
a.setval(1) a.setval(1)
expect(a).to eq 1 expect(a).to eq 1
end end
it "should propagate values when we call setval" do it "should propagate values when we call #setval" do
a=Port.new(4) a=Port.new(4)
b=Port.new(4) b=Port.new(4)
c=Port.new(4) c=Port.new(4)
@ -42,4 +42,10 @@ describe Port do
a=Port.new(4) a=Port.new(4)
expect {a.setval(16)}.to raise_error ArgumentError expect {a.setval(16)}.to raise_error ArgumentError
end 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 end