Skip to content

Instantly share code, notes, and snippets.

@mirichi
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mirichi/c5e8bb02e790c5d3088b to your computer and use it in GitHub Desktop.
Save mirichi/c5e8bb02e790c5d3088b to your computer and use it in GitHub Desktop.
ハードウェアシミュレータ6/19
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)
tmp = @value
@value = v
# 出力が変わったら通知先をキューに格納する
if tmp != v
@output_objects.each do |i|
QUEUE.push 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
if @a.get != nil or @b.get != nil
@o.set(!(@a.get and @b.get))
end
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 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
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
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment