🚥
Rubyのコードで理解するシフトレジスタのカスケード接続
前回と今回やること
前回はシリアルデータを1バイトに変換する仕組みを学んだ。今回はシフトレジスタをカスケード接続して1バイトを超えるデータを扱う仕組みをシミュレートする。
シフトレジスタ単体
class Storage
BIT = 8
attr_writer :input
attr_reader :values
attr_reader :carry
def initialize
@values = Array.new(BIT) { 0 }
end
def shift
@values.unshift(@input)
@carry = @values.pop
end
def shift_out(value)
BIT.pred.downto(0) do |i|
self.input = value[i]
shift
end
end
def to_i
@values.each.with_index.sum { |e, i| e << i }
end
def inspect
"%0*b (%d)" % [BIT, to_i, to_i]
end
end
動作確認
S = Storage.new
S.shift_out(128)
S # => 10000000 (128)
S.input = 0
S.shift
S # => 00000000 (0)
S.carry # => 1
左シフトすると溢れた MSB が carry に入る。
複数のシフトレジスタを繋ぐ
class BigStorage
def initialize(count)
@storages = Array.new(count) { Storage.new }
end
def shift_out(value)
(@storages.size * Storage::BIT).pred.downto(0) do |i|
self.input = value[i]
shift
end
end
def input=(value)
@storages.first.input = value
end
def shift
[*@storages, nil].each_cons(2) do |a, b|
a.shift
if b
b.input = a.carry
end
end
end
def to_i
@storages.flat_map(&:values).each.with_index.sum { |e, i| e << i }
end
def inspect
"%0*b (%d)" % [@storages.size * Storage::BIT, to_i, to_i]
end
end
動作確認
S = BigStorage.new(2)
S.shift_out(128)
S # => 0000000010000000 (128)
S.input = 0
S.shift
S # => 0000000100000000 (256)
単体のときと同様に左シフトすると MSB が2つ目のシフトレジスタに渡る。このようにシフトレジスタを増やせばいくらでも大きな数を扱えるようになる。
S = BigStorage.new(4)
S.shift_out(-1)
S # => 11111111111111111111111111111111 (4294967295)
Discussion