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"
|
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
17
port.rb
@ -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
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"
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user