-
-
Save mirichi/68f6b8da18574a6815071bd05d316262 to your computer and use it in GitHub Desktop.
ハードウェアシミュレータ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
HLHASH = {true=>"H", false=>"L", nil=>"nil"} | |
H = true | |
L = false | |
QUEUE = [] | |
# 出力ピン | |
class OutputPin | |
attr_accessor :output_objects | |
def initialize(v=nil) | |
@value = v | |
@output_objects = [] | |
end | |
# 出力をセットする | |
def set(v) | |
# 出力が変わったら通知先をキューに格納する | |
if @value != v | |
@value = v | |
@output_objects.each do |i| | |
QUEUE << i | |
end | |
end | |
self | |
end | |
# 出力の取得 | |
def get | |
@value | |
end | |
# &演算子 | |
def &(dst) | |
tmp = AND.new | |
tmp.a = self | |
tmp.b = dst | |
tmp.o | |
end | |
# |演算子 | |
def |(dst) | |
tmp = OR.new | |
tmp.a = self | |
tmp.b = dst | |
tmp.o | |
end | |
# ~演算子 | |
def ~ | |
tmp = NOT.new | |
tmp.a = self | |
tmp.o | |
end | |
# ^演算子 | |
def ^(dst) | |
tmp = XOR.new | |
tmp.a = self | |
tmp.b = dst | |
tmp.o | |
end | |
end | |
# 外部からの入力用配線 | |
class Line | |
attr_accessor :output_objects | |
def initialize | |
@o = OutputPin.new | |
@output_objects = [] | |
end | |
def d=(v) | |
@d = OutputPin.new(v) | |
QUEUE.push(self) | |
# キューが無くなるまでシミュレーション実行 | |
while QUEUE.size > 0 | |
QUEUE.shift.update | |
end | |
end | |
def o | |
@o | |
end | |
def update | |
@o.set(@d.get) | |
end | |
end | |
class Bus1 | |
def initialize | |
@o = OutputPin.new | |
end | |
def o | |
@o | |
end | |
def add(v) | |
v.connect_bus(self) | |
end | |
end | |
class Bus | |
def initialize(bit_width) | |
@bus = Array.new(bit_width){Bus1.new} | |
end | |
def o | |
@bus.map{|b|b.o} | |
end | |
def add(v) | |
v.connect_bus(@bus) | |
end | |
def bus | |
@bus | |
end | |
end | |
class ThreeStateBuffer1 | |
def d=(v) | |
v.output_objects << self | |
@d = v | |
QUEUE.push self if v.get != nil | |
end | |
def g=(v) | |
v.output_objects << self | |
@g = v | |
QUEUE.push self if v.get != nil | |
end | |
def update | |
@bus.o.set(@d.get) if @g and @g.get | |
end | |
def connect_bus(b) | |
@bus = b | |
end | |
end | |
class ThreeStateBuffer | |
def initialize(bit_width) | |
@tsb = Array.new(bit_width){ThreeStateBuffer1.new} | |
end | |
def d=(v) | |
@tsb.zip(v) do |tsb, o| | |
tsb.d = o | |
end | |
end | |
def g=(v) | |
@tsb.each do |tsb| | |
tsb.g = v | |
end | |
end | |
def connect_bus(b) | |
@tsb.zip(b).each do |t, bus| | |
t.connect_bus bus | |
end | |
end | |
end | |
class ThreeStateBufferB1 | |
def d=(v) | |
v.output_objects << self | |
@d = v | |
QUEUE.push self if v.get != nil | |
end | |
def g=(v) | |
v.output_objects << self | |
@g = v | |
QUEUE.push self if v.get != nil | |
end | |
def update | |
@bus.o.set(@d.get) if @g and !@g.get | |
end | |
def connect_bus(b) | |
@bus = b | |
end | |
end | |
class ThreeStateBufferB | |
def initialize(bit_width) | |
@tsb = Array.new(bit_width){ThreeStateBufferB1.new} | |
end | |
def d=(v) | |
@tsb.zip(v) do |tsb, o| | |
tsb.d = o | |
end | |
end | |
def g=(v) | |
@tsb.each do |tsb| | |
tsb.g = v | |
end | |
end | |
def connect_bus(b) | |
@tsb.zip(b).each do |t, bus| | |
t.connect_bus bus | |
end | |
end | |
end | |
# NANDゲート試作 | |
class NAND | |
def initialize | |
@o = OutputPin.new | |
@a = @b = OutputPin.new | |
end | |
def a=(v) | |
v.output_objects << self | |
@a = v | |
QUEUE.push self if v.get != nil | |
end | |
def b=(v) | |
v.output_objects << self | |
@b = v | |
QUEUE.push self if v.get != nil | |
end | |
def o | |
@o | |
end | |
def update | |
@o.set(!(@a.get and @b.get)) | |
end | |
def inspect | |
"#{HLHASH[o.get]}" | |
end | |
end | |
# NOTゲート試作 | |
class NOT | |
def initialize | |
@nand = NAND.new | |
end | |
def a=(v) | |
@nand.a = v | |
@nand.b = v | |
end | |
def o | |
@nand.o | |
end | |
def inspect | |
"#{HLHASH[o.get]}" | |
end | |
end | |
class AND | |
def initialize | |
@nand = NAND.new | |
@not = NOT.new | |
@not.a = @nand.o | |
end | |
def a=(v) | |
@nand.a = v | |
end | |
def b=(v) | |
@nand.b = v | |
end | |
def o | |
@not.o | |
end | |
def inspect | |
"#{HLHASH[o.get]}" | |
end | |
end | |
class OR | |
def initialize | |
@nand = NAND.new | |
@not1 = NOT.new | |
@not2 = NOT.new | |
@nand.a = @not1.o | |
@nand.b = @not2.o | |
end | |
def a=(v) | |
@not1.a = v | |
end | |
def b=(v) | |
@not2.a = v | |
end | |
def o | |
@nand.o | |
end | |
def inspect | |
"#{HLHASH[o.get]}" | |
end | |
end | |
class XOR | |
def initialize | |
@and1 = AND.new | |
@and2 = AND.new | |
@not1 = NOT.new | |
@not2 = NOT.new | |
@or = OR.new | |
@and1.a = @not1.o | |
@and2.b = @not2.o | |
@or.a = @and1.o | |
@or.b = @and2.o | |
end | |
def a=(v) | |
@not1.a = v | |
@and2.a = v | |
end | |
def b=(v) | |
@not2.a = v | |
@and1.b = v | |
end | |
def o | |
@or.o | |
end | |
def inspect | |
"#{HLHASH[o.get]}" | |
end | |
end | |
class NAND3 | |
def initialize | |
@nand = NAND.new | |
@and = AND.new | |
@nand.a = @and.o | |
end | |
def a=(v) | |
@nand.b = v | |
end | |
def b=(v) | |
@and.a = v | |
end | |
def c=(v) | |
@and.b = v | |
end | |
def o | |
@nand.o | |
end | |
def inspect | |
"#{HLHASH[o.get]}" | |
end | |
end | |
class HarfAdder | |
def initialize | |
@and = AND.new | |
@xor = XOR.new | |
end | |
def a=(v) | |
@and.a = v | |
@xor.a = v | |
end | |
def b=(v) | |
@and.b = v | |
@xor.b = v | |
end | |
def s | |
@xor.o | |
end | |
def c | |
@and.o | |
end | |
def inspect | |
"#{HLHASH[c.get]}#{HLHASH[s.get]}" | |
end | |
end | |
class FullAdder | |
def initialize | |
@hadr1 = HarfAdder.new | |
@hadr2 = HarfAdder.new | |
@or = OR.new | |
@hadr2.a = @hadr1.s | |
@or.a = @hadr1.c | |
@or.b = @hadr2.c | |
end | |
def a=(v) | |
@hadr1.a = v | |
end | |
def b=(v) | |
@hadr1.b = v | |
end | |
def x=(v) | |
@hadr2.b = v | |
end | |
def s | |
@hadr2.s | |
end | |
def c | |
@or.o | |
end | |
def inspect | |
"#{HLHASH[c.get]}#{HLHASH[s.get]}" | |
end | |
end | |
class RSFF | |
def initialize | |
@not1 = NOT.new | |
@not2 = NOT.new | |
@nand1 = NAND.new | |
@nand2 = NAND.new | |
@nand1.a = @not1.o | |
@nand1.b = @nand2.o | |
@nand2.a = @not2.o | |
@nand2.b = @nand1.o | |
end | |
def s=(v) | |
@not1.a = v | |
end | |
def r=(v) | |
@not2.a = v | |
end | |
def q | |
@nand1.o | |
end | |
def qb | |
@nand2.o | |
end | |
def inspect | |
"q=#{HLHASH[q.get]}, qb=#{HLHASH[qb.get]}" | |
end | |
end | |
class DFF1 | |
def initialize | |
@not1 = NOT.new | |
@not2 = NOT.new | |
@nand1 = NAND.new | |
@nand2 = NAND.new | |
@nand3 = NAND.new | |
@nand4 = NAND.new | |
@nand5 = NAND.new | |
@nand6 = NAND.new | |
@nand7 = NAND.new | |
@nand8 = NAND.new | |
@reset1_and = AND.new | |
@reset1_not = NOT.new | |
@reset1_nand = NAND.new | |
@reset1_and.a = @nand2.o | |
@reset1_not.a = @nand1.o | |
@reset1_nand.a = @reset1_not.o | |
@reset2_and = AND.new | |
@reset2_not = NOT.new | |
@reset2_nand = NAND.new | |
@reset2_and.a = @nand6.o | |
@reset2_not.a = @nand5.o | |
@reset2_nand.a = @reset2_not.o | |
@not2.a = @not1.o | |
@nand1.b = @not1.o | |
@nand2.a = @nand1.o | |
@nand2.b = @not1.o | |
@nand3.a = @reset1_nand.o | |
@nand3.b = @nand4.o | |
@nand4.a = @nand3.o | |
@nand4.b = @reset1_and.o | |
@nand5.a = @nand3.o | |
@nand5.b = @not2.o | |
@nand6.a = @nand5.o | |
@nand6.b = @not2.o | |
@nand7.a = @reset2_nand.o | |
@nand7.b = @nand8.o | |
@nand8.a = @nand7.o | |
@nand8.b = @reset2_and.o | |
end | |
def d=(v) | |
@nand1.a = v | |
end | |
def clk=(v) | |
@not1.a = v | |
end | |
def clrb=(v) | |
@reset1_and.b = @reset1_nand.b = v | |
@reset2_and.b = @reset2_nand.b = v | |
end | |
def q | |
@nand7.o | |
end | |
def qb | |
@nand8.o | |
end | |
def inspect | |
"q=#{HLHASH[q.get]}, qb=#{HLHASH[qb.get]}" | |
end | |
end | |
class DFF | |
def initialize(bit_width) | |
@dff = Array.new(bit_width){DFF1.new} | |
end | |
def d=(v) | |
@dff.zip(v) do |dff, o| | |
dff.d = o | |
end | |
end | |
def clk=(v) | |
@dff.each do |dff| | |
dff.clk = v | |
end | |
end | |
def clrb=(v) | |
@dff.each do |dff| | |
dff.clrb = v | |
end | |
end | |
def q | |
@dff.map{|dff|dff.q} | |
end | |
def qb | |
@dff.map{|dff|dff.qb} | |
end | |
end | |
class JKFF | |
def initialize | |
@nand1 = NAND.new | |
@nand2 = NAND.new | |
@nand3 = NAND.new | |
@nand4 = NAND3.new | |
@nand5 = NAND3.new | |
@nand6 = NAND.new | |
@nand7 = NAND.new | |
@nand8 = NAND.new | |
@reset_and = AND.new | |
@reset_not = NOT.new | |
@reset_nand = NAND.new | |
@reset_and.a = @nand5.o | |
@reset_not.a = @nand4.o | |
@reset_nand.a = @reset_not.o | |
@nand1.a = @nand8.o | |
@nand2.b = @nand7.o | |
@nand3.a = @nand1.o | |
@nand3.b = @nand4.o | |
@nand4.a = @nand3.o | |
@nand4.c = @nand5.o | |
@nand5.a = @nand4.o | |
@nand5.c = @nand6.o | |
@nand6.a = @nand5.o | |
@nand6.b = @nand2.o | |
@nand7.a = @reset_nand.o # @nand.o | |
@nand7.b = @nand8.o | |
@nand8.a = @nand7.o | |
@nand8.b = @reset_and.o #@nand5.o | |
end | |
def j=(v) | |
@nand1.b = v | |
end | |
def k=(v) | |
@nand2.a = v | |
end | |
def clk=(v) | |
@nand4.b = v | |
@nand5.b = v | |
end | |
def clrb=(v) | |
@reset_and.b = @reset_nand.b = v | |
end | |
def q | |
@nand7.o | |
end | |
def qb | |
@nand8.o | |
end | |
def inspect | |
"#{HLHASH[q.get]}#{HLHASH[qb.get]}" | |
end | |
end | |
class TFF | |
def initialize | |
@jkff = JKFF.new | |
@jkff.j = @jkff.k = OutputPin.new(H) | |
end | |
def t=(v) | |
@jkff.clk = v | |
end | |
def clrb=(v) | |
@jkff.clrb = v | |
end | |
def q | |
@jkff.q | |
end | |
def qb | |
@jkff.qb | |
end | |
def inspect | |
"#{HLHASH[q.get]}#{HLHASH[qb.get]}" | |
end | |
end | |
class Incrementer | |
def initialize(bit_width) | |
@ha = Array.new(bit_width){HarfAdder.new} | |
@ha.last.b = OutputPin.new(H) | |
if bit_width > 1 | |
(bit_width-1).times do |i| | |
@ha[i].b = @ha[i+1].c | |
end | |
end | |
end | |
def d=(v) | |
@ha.zip(v).each do |ha, o| | |
ha.a = o | |
end | |
end | |
def o | |
@ha.map{|ha|ha.s} | |
end | |
end | |
class Counter | |
def initialize(bit_width) | |
@dff = Array.new(bit_width){ | |
tmp = DFF1.new | |
tmp.d = tmp.qb | |
tmp | |
} | |
if bit_width > 1 | |
(bit_width-1).times do |i| | |
@dff[i].clk = @dff[i+1].qb | |
end | |
end | |
end | |
def clk=(v) | |
@dff.last.clk = v | |
end | |
def clrb=(v) | |
@dff.each do |dff| | |
dff.clrb = v | |
end | |
end | |
def o | |
@dff.map{|dff|dff.q} | |
end | |
end | |
# 単純なバッファ | |
class Buffer1 | |
def initialize | |
@not1 = NOT.new | |
@not2 = NOT.new | |
@not1.a = @not2.o | |
end | |
def d=(v) | |
@not2.a = v | |
end | |
def o | |
@not1.o | |
end | |
end | |
# 単純なバッファの塊 | |
class Buffer | |
def initialize(bit_width) | |
@buf = Array.new(bit_width){Buffer1.new} | |
end | |
def d=(v) | |
@buf.zip(v) do |buf, o| | |
buf.d = o | |
end | |
end | |
def o | |
@buf.map{|b|b.o} | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
# 1bitデータ2つを1bitで選択するマルチプレクサ(スリーステートバッファ版) | |
class Mux1_1 | |
def initialize | |
@tsb0 = ThreeStateBufferB1.new | |
@tsb1 = ThreeStateBuffer1.new | |
@bus = Bus1.new | |
@bus.add(@tsb0) | |
@bus.add(@tsb1) | |
end | |
def s=(v) | |
@tsb0.g = @tsb1.g = v | |
end | |
def d0=(v) | |
@tsb0.d = v | |
end | |
def d1=(v) | |
@tsb1.d = v | |
end | |
def o | |
@bus.o | |
end | |
end | |
# n bitデータ2つを1bitで選択するマルチプレクサ | |
class Mux1_n | |
def initialize(bit_width) | |
@mux = Array.new(bit_width){Mux1_1.new} | |
end | |
def s=(v) | |
@mux.each do |m| | |
m.s = v | |
end | |
end | |
def d=(v) | |
@mux.zip(*v) do |m, d1, d0| | |
m.d1 = d1 | |
m.d0 = d0 | |
end | |
end | |
def o | |
@mux.map{|m|m.o} | |
end | |
end | |
# n bitデータをn bitで選択するマルチプレクサ | |
class Mux | |
def initialize(select_bit_width, data_bit_width) | |
# 作成 | |
@mux = Array.new(select_bit_width){|i| Array.new(2**i){Mux1_n.new(data_bit_width)}} | |
@buf = Buffer.new(select_bit_width) | |
# 選択線接続 | |
@mux.zip(@buf.o).each do |ary, b| | |
ary.each do |m| | |
m.s = b | |
end | |
end | |
# データ線接続 | |
if select_bit_width > 1 | |
(1...select_bit_width).each do |i| | |
@mux[i-1].each.with_index do |m, j| | |
m.d = [@mux[i][j * 2].o, @mux[i][j * 2 + 1].o] | |
end | |
end | |
end | |
end | |
def s=(v) | |
@buf.d = v | |
end | |
def d=(v) | |
@mux.last.each.with_index do |m, i| | |
m.d = [v[i * 2], v[i * 2 + 1]] | |
end | |
end | |
def o | |
@mux[0][0].o | |
end | |
end | |
# n bitの入力から2**n bitのどれかを選択してHにするセレクタ | |
class Selector | |
def initialize(bit_width) | |
@buf = Buffer.new(bit_width) | |
tmp = NOT.new | |
tmp.a = @buf.o[0] | |
@o = [@buf.o[0], tmp.o] | |
# 複数bit時の接続 | |
if bit_width > 1 | |
(bit_width-1).times do |i| | |
tmp = NOT.new | |
tmp.a = @buf.o[i+1] | |
bary = [@buf.o[i+1]]*(@o.size) + [tmp.o]*(@o.size) | |
@o = @o * 2 | |
@o = @o.zip(bary).map do |o, b| | |
a = AND.new | |
a.a = o | |
a.b = b | |
a.o | |
end | |
end | |
end | |
end | |
def s=(v) | |
# 苦労して作ったら順番が逆だったのでreverseしてごまかす | |
@buf.d = v.reverse | |
end | |
def o | |
@o | |
end | |
end | |
# 可変長加算器 | |
class Adder | |
def initialize(bit_width) | |
@adder = Array.new(bit_width){FullAdder.new} | |
# 2bit以上の加算の場合、加算器同士を接続する | |
if bit_width > 1 | |
@adder[0..-2].each.with_index do |a, i| | |
a.x = @adder[i+1].c | |
end | |
end | |
end | |
# データ入力 | |
def d=(v) | |
@adder.zip(*v).each do |a, d1, d0| | |
a.a = d1 | |
a.b = d0 | |
end | |
end | |
# キャリー入力 | |
def x=(v) | |
@adder.last.x = v | |
end | |
# キャリー出力 | |
def c | |
@adder[0].c | |
end | |
# 出力 | |
def o | |
@adder.map{|a|a.s} | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
# 指定ビットシフトする(論理、算術共有)(-が左、+が右) | |
class Shifter | |
def initialize(bit_width, n) | |
@buf = Buffer.new(bit_width) | |
@n = n | |
@sign = Buffer1.new | |
end | |
def d=(v) | |
@buf.d = Array.new(@buf.o.size) do |i| | |
if i - @n < 0 | |
@sign.o | |
elsif i - @n >= @buf.o.size | |
OutputPin.new(L) | |
else | |
v[i - @n] | |
end | |
end | |
end | |
# 右シフトの場合、ここに最上位ビットの出力ピンを接続すると算術シフト、L固定にすると論理シフト。 | |
# 左シフトの場合は使われないのでどっちでもいい。 | |
def sign=(v) | |
@sign.d = v | |
end | |
def o | |
@buf.o | |
end | |
end | |
# バレルシフタ | |
class BarrelShifter | |
def initialize(shift_bit_width, data_bit_width) | |
# 左シフタ | |
@lshifter = Array.new(shift_bit_width){|i| Shifter.new(data_bit_width, -(2**i))} | |
@lmux = Array.new(shift_bit_width){Mux1_n.new(data_bit_width)} | |
@lbuf = Buffer.new(shift_bit_width) | |
# 右シフタ | |
@rshifter = Array.new(shift_bit_width){|i| Shifter.new(data_bit_width, 2**i)} | |
@rmux = Array.new(shift_bit_width){Mux1_n.new(data_bit_width)} | |
@rbuf = Buffer.new(shift_bit_width) | |
# 接続 | |
shift_bit_width.times do |i| | |
@lmux[i].s = @lbuf.o[i] | |
@rmux[i].s = @rbuf.o[i] | |
if i > 0 | |
@lshifter[i].d = @lmux[i-1].o | |
@lmux[i].d = [@lshifter[i].o, @lmux[i-1].o] | |
@rshifter[i].d = @rmux[i-1].o | |
@rmux[i].d = [@rshifter[i].o, @rmux[i-1].o] | |
end | |
end | |
# 左右選択マルチプレクサ | |
@mux = Mux1_n.new(data_bit_width) | |
@mux.d = [@rmux.last.o, @lmux.last.o] | |
end | |
# データ入力 | |
def d=(v) | |
@lshifter[0].d = @rshifter[0].d = v | |
@lmux[0].d = @rmux[0].d = [@rshifter[0].o, v] | |
end | |
# シフトビット数 | |
def shift=(v) | |
@lbuf.d = @rbuf.d = v.reverse | |
end | |
# 算術シフトの場合に最上位に埋められる符号ビット | |
def sign=(v) | |
@lshifter.each do |s| | |
s.sign = v | |
end | |
@rshifter.each do |s| | |
s.sign = v | |
end | |
end | |
# Lが左、Hが右 | |
def direction=(v) | |
@mux.s = v | |
end | |
def o | |
@mux.o | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
# 符号なし乗算器 | |
class Multiplier | |
def initialize(bit_width) | |
# 入力線 | |
@buf0 = Buffer.new(bit_width) | |
@buf1 = Buffer.new(bit_width) | |
# L固定の出力ピン | |
opl = OutputPin.new(L) | |
# シフトした配列を作る | |
buf = Array.new(bit_width) do |i| | |
tmp1 = [opl] * (bit_width * 2) # Lの出力ピンをbit_width*2だけ並べた配列 | |
tmp2 = @buf0.o.map{|b|b & @buf1.o[bit_width - i - 1]} # buf0の各bitとbuf1の1bitのandを取る | |
tmp1[bit_width - i, bit_width] = tmp2 # tmp1配列の一部をtmp2に差し替える | |
tmp1 | |
end | |
# シフトした値を加算するための加算器 | |
@adder = Array.new(Math.log(bit_width, 2)){|i|Array.new(2**i){Adder.new(bit_width*2)}} | |
@adder.last.each.with_index do |adder, i| | |
adder.d = [buf[i * 2], buf[i * 2 + 1]] | |
adder.x = opl | |
end | |
(1...(@adder.size)).each do |i| | |
@adder[i-1].each.with_index do |adder, j| | |
adder.d = [@adder[i][j * 2].o, @adder[i][j * 2 + 1].o] | |
adder.x = opl | |
end | |
end | |
end | |
def d=(v) | |
@buf0.d = v[0] | |
@buf1.d = v[1] | |
end | |
def o | |
@adder[0][0].o | |
end | |
end | |
# 符号あり乗算器 | |
class SignedMultiplier | |
def initialize(bit_width) | |
# 入力線 | |
@buf0 = Buffer.new(bit_width) | |
@buf1 = Buffer.new(bit_width) | |
# HL固定の出力ピン | |
oph = OutputPin.new(H) | |
opl = OutputPin.new(L) | |
# シフトした配列を作る | |
@buf = Array.new(bit_width) do |i| | |
tmp1 = [opl] * (bit_width * 2) # Lの出力ピンをbit_width*2だけ並べた配列 | |
tmp2 = @buf1.o[bit_width - i - 1] | |
if i == (bit_width-1) # 最後のみ | |
# 先頭以外反転 | |
tmp2 = [@buf0.o[0] & tmp2] + @buf0.o[1..-1].map{|b|~(b & tmp2)} | |
else | |
# 先頭だけ反転 | |
tmp2 = [~(@buf0.o[0] & tmp2)] + @buf0.o[1..-1].map{|b|b & tmp2} | |
end | |
tmp1[bit_width - i, bit_width] = tmp2 # tmp1配列の一部をtmp2に差し替える | |
if i == (bit_width-1) or i == 0 # 最初と最後 | |
tmp1[bit_width - i - 1] = oph | |
end | |
tmp1 | |
end | |
# シフトした値を加算するための加算器 | |
@adder = Array.new(Math.log(bit_width, 2)){|i|Array.new(2**i){Adder.new(bit_width*2)}} | |
@adder.last.each.with_index do |adder, i| | |
adder.d = [@buf[i * 2], @buf[i * 2 + 1]] | |
adder.x = opl | |
end | |
(1...(@adder.size)).each do |i| | |
@adder[i-1].each.with_index do |adder, j| | |
adder.d = [@adder[i][j*2].o, @adder[i][j*2+1].o] | |
adder.x = opl | |
end | |
end | |
end | |
def d=(v) | |
@buf0.d = v[0] | |
@buf1.d = v[1] | |
end | |
def o | |
@adder[0][0].o | |
end | |
end | |
# ROM | |
class ROM | |
def initialize(select_bit_width, data_bit_width) | |
@mux = Mux.new(select_bit_width, data_bit_width) | |
@tsb = ThreeStateBufferB.new(data_bit_width) | |
@tsb.d = @mux.o | |
end | |
# アドレス線 | |
def a=(v) | |
@mux.s = v | |
end | |
# チップセレクト | |
def csb=(v) | |
@tsb.g = v | |
end | |
# 保持データの接続 | |
def d=(v) | |
@mux.d = v | |
end | |
# 出力(スリーステートバッファ) | |
def o | |
@tsb | |
end | |
end | |
# レジスタ | |
class Register | |
def initialize(bit_width) | |
@dff = DFF.new(bit_width) | |
@mux = Mux1_n.new(bit_width) | |
@dff.d = @mux.o | |
end | |
def clk=(v) | |
@dff.clk = v | |
end | |
def d=(v) | |
@mux.d = [v, self.o] | |
end | |
# 書き込む場合にH | |
def w=(v) | |
@mux.s = v | |
end | |
def clrb=(v) | |
@dff.clrb = v | |
end | |
def o | |
@dff.q | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
# レジスタファイル(出力2ポート、入力1ポート)。ゼロ番はゼロレジスタになる | |
class RegisterFile | |
def initialize(select_bit_width, data_bit_width) | |
# レジスタの配列 | |
@reg = Array.new(2**select_bit_width){Register.new(data_bit_width)} | |
# 書き込みレジスタを選択するためのセレクタ | |
# セレクタの出力はレジスタファイルのW信号入力とANDを取って各レジスタのWに入る | |
@sel = Selector.new(select_bit_width) | |
@w = Buffer1.new # W入力用バッファ | |
@reg.zip(@sel.o).each do |reg, sel| | |
if @sel.o[-1] != sel # 最後の1個じゃない場合 | |
reg.w = @w.o & sel # &演算子でANDゲートが生成される。戻りはANDゲートの出力ピン | |
else # 最後の1個(ゼロレジスタ)の場合 | |
reg.w = OutputPin.new(L) # つねにL。つまり書き込みは行われない | |
end | |
end | |
# 出力ポート | |
@mux0 = Mux.new(select_bit_width, data_bit_width) | |
@mux0.d = self.o | |
@mux1 = Mux.new(select_bit_width, data_bit_width) | |
@mux1.d = self.o | |
end | |
# クロック入力 | |
# 書き込みタイミングはクロックの立ち上がり | |
def clk=(v) | |
@reg.each do |reg| | |
reg.clk = v | |
end | |
end | |
# select_bit_width本の書き込み選択信号 | |
# 内部のセレクタに入力される | |
def sin=(v) | |
@sel.s = v | |
end | |
# 出力ポート0用選択信号 | |
def sout0=(v) | |
@mux0.s = v | |
end | |
# 出力ポート1用選択信号 | |
def sout1=(v) | |
@mux1.s = v | |
end | |
# 入力データ | |
# wがHの場合、クロックの立ち上がりでsで選択されたレジスタにデータが書き込まれる | |
def d=(v) | |
@reg.each do |reg| | |
reg.d = v | |
end | |
end | |
# 入力ポート有効がH | |
def w=(v) | |
@w.d = v | |
end | |
# クリア信号 | |
def clrb=(v) | |
@reg.each do |reg| | |
reg.clrb = v | |
end | |
end | |
# 出力ポート0の出力 | |
def o0 | |
@mux0.o | |
end | |
# 出力ポート1の出力 | |
def o1 | |
@mux1.o | |
end | |
# 出力(全レジスタ) | |
def o | |
@reg.map{|r|r.o} | |
end | |
end | |
# ANDの塊 | |
class ANDn | |
def initialize(bit_width) | |
@and = Array.new(bit_width){AND.new} | |
end | |
def a=(v) | |
@and.zip(v) do |n, o| | |
n.a = o | |
end | |
end | |
def b=(v) | |
@and.zip(v) do |n, o| | |
n.b = o | |
end | |
end | |
def o | |
@and.map{|n|n.o} | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
# ORの塊 | |
class ORn | |
def initialize(bit_width) | |
@or = Array.new(bit_width){OR.new} | |
end | |
def a=(v) | |
@or.zip(v) do |n, o| | |
n.a = o | |
end | |
end | |
def b=(v) | |
@or.zip(v) do |n, o| | |
n.b = o | |
end | |
end | |
def o | |
@or.map{|n|n.o} | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
# XORの塊 | |
class XORn | |
def initialize(bit_width) | |
@xor = Array.new(bit_width){XOR.new} | |
end | |
def a=(v) | |
@xor.zip(v) do |n, o| | |
n.a = o | |
end | |
end | |
def b=(v) | |
@xor.zip(v) do |n, o| | |
n.b = o | |
end | |
end | |
def o | |
@xor.map{|n|n.o} | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
# NOTの塊 | |
class NOTn | |
def initialize(bit_width) | |
@not = Array.new(bit_width){NOT.new} | |
end | |
def a=(v) | |
@not.zip(v) do |n, o| | |
n.a = o | |
end | |
end | |
def o | |
@not.map{|n|n.o} | |
end | |
def inspect | |
o.map{|o|"#{HLHASH[o.get]}"}.join | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment