-
-
Save mirichi/9553e68fbec4c90660d2 to your computer and use it in GitHub Desktop.
add reg, immを実装した
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
require './hsim' | |
# 単純なバッファ | |
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 | |
# ROM | |
class ROM | |
def initialize(select_bit_width, data_bit_width) | |
@mux = Mux.new(select_bit_width, data_bit_width) | |
@tsb = ThreeStateBuffer.new(data_bit_width) | |
@not = NOT.new | |
@tsb.d = @mux.o | |
@tsb.g = @not.o | |
end | |
# アドレス線 | |
def a=(v) | |
@mux.s = v | |
end | |
# チップセレクト | |
def csb=(v) | |
@not.a = v | |
end | |
# 保持データの接続 | |
def d=(v) | |
@mux.d = v | |
end | |
# 出力(スリーステートバッファ) | |
def o | |
@tsb | |
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 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 | |
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| | |
reg.w = @w.o & sel # &演算子でANDゲートが生成される。戻りはANDゲートの出力ピン | |
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 | |
# 可変長加算器 | |
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 | |
# 電源とグランド | |
_vcc = Line.new | |
_gnd = Line.new | |
vcc = _vcc.o | |
gnd = _gnd.o | |
# ROM | |
rom = ROM.new(3, 8) # アドレス線3本、データ線8本 | |
rom.d = [ # 8アドレスぶんのデータ | |
[gnd, gnd, gnd, gnd, gnd, vcc, gnd, gnd], # mov a, 0x1 | |
[gnd, gnd, gnd, gnd, vcc, gnd, gnd, vcc], # mov b, 0x2 | |
[gnd, gnd, gnd, gnd, vcc, vcc, vcc, gnd], # mov c, 0x3 | |
[gnd, gnd, gnd, vcc, gnd, gnd, vcc, vcc], # mov d, 0x4 | |
[gnd, vcc, gnd, vcc, gnd, vcc, gnd, gnd], # add a, 0x5 | |
[gnd, vcc, gnd, vcc, gnd, vcc, gnd, vcc], # add b, 0x5 | |
[gnd, vcc, vcc, gnd, vcc, gnd, vcc, gnd], # add c, 0xa | |
[gnd, vcc, vcc, gnd, vcc, gnd, vcc, vcc] # add d, 0xa | |
].reverse | |
# 8bitデータバス | |
bus = Bus.new(8) | |
# クロックとクリアの入力線 | |
clk = Line.new | |
clrb = Line.new | |
# 4bitカウンタ | |
c4 = Counter.new(4) | |
c4.clk = clk.o | |
c4.clrb = clrb.o | |
# ROMにカウンタの値を接続 | |
rom.a = [c4.o[1], c4.o[2], c4.o[3]] | |
rom.csb = c4.o[0] | |
# ROMの出力はThreeStateBufferなのでBusオブジェクトにaddする | |
bus.add rom.o | |
# ROMの出力の値はBusオブジェクトから取り出す | |
# 循環接続するので先に生成しておく | |
regf = RegisterFile.new(2, 4) # レジスタファイル | |
adder = Adder.new(4) # 加算器 | |
muxd = Mux1_n.new(4) # 書き込みデータ選択用マルチプレクサ | |
# 4bitレジスタ4本のレジスタファイル | |
regf.clk = clk.o | |
regf.clrb = clrb.o | |
# 出力ポートの接続 | |
regf.sout0 = bus.o[6..7] | |
# 入力ポートの接続 | |
regf.d = muxd.o | |
regf.sin = bus.o[6..7] # 命令的に出力と同じレジスタが選択される | |
regf.w = vcc # 書き込まない命令が存在しないので常に書き込む指定 | |
# 4bit全加算器 | |
adder.d = [regf.o0, bus.o[2..5]] # レジスタファイルの出力ポート0とROMのデータを加算する | |
adder.x = gnd # キャリー入力は今のところ使わないのでL固定としておく | |
# キャリー出力は使わないので接続しない | |
# キャリーフラグを追加するときにそこに接続する予定 | |
# movとaddの命令によってROMの値か加算器を通した値かを選択するマルチプレクサ | |
muxd.d = [adder.o, bus.o[2..5]] | |
muxd.s = bus.o[1] | |
# 電源接続 | |
_vcc.d = H | |
_gnd.d = L | |
# 簡易ロジックアナライザ | |
require 'dxruby' | |
module LogicAnalyzer | |
@@probes = [] | |
def self.probes | |
@@probes | |
end | |
class Probe < Struct.new(:name, :outpin) | |
end | |
def self.analyze(&b) | |
f = Fiber.new(&b) | |
buf = [] | |
# 実行 | |
while f.resume(:la) != :la | |
tmp = [] | |
@@probes.each do |pr| | |
tmp.push(pr.outpin.get) | |
end | |
buf.push(tmp) | |
end | |
image = Image.new(640, 480) | |
size = 480 / @@probes.size | |
font = Font.new(size) | |
x = @@probes.map{|v|font.get_width(v.name)}.max + 15 | |
# 画像作成 | |
@@probes.each.with_index do |pr, i| | |
image.draw_font(10, i * size, pr.name, font) | |
tmp = false | |
buf.each.with_index do |b, j| | |
if tmp != b[i] | |
image.line(j * 10 + x, i * size + 8, j * 10 + x, i * size + size - 1, C_WHITE) | |
end | |
image.line(j * 10 + x, i * size + (b[i] ? 8 : size - 1), j * 10 + x + 10, i * size + (b[i] ? 8 : size - 1), C_WHITE) | |
tmp = b[i] | |
end | |
end | |
Window.loop do | |
Window.draw(0, 0, image) | |
break if Input.key_push?(K_ESCAPE) | |
end | |
end | |
end | |
# プローブ接続 | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("clk", clk.o) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("d b0", bus.o[7]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("d b1", bus.o[6]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("d b2", bus.o[5]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("d b3", bus.o[4]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("d b4", bus.o[3]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("d b5", bus.o[2]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("d b6", bus.o[1]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("areg b0", regf.o[3][3]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("areg b1", regf.o[3][2]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("areg b2", regf.o[3][1]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("areg b3", regf.o[3][0]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("breg b0", regf.o[2][3]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("breg b1", regf.o[2][2]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("breg b2", regf.o[2][1]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("breg b3", regf.o[2][0]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("creg b0", regf.o[1][3]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("creg b1", regf.o[1][2]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("creg b2", regf.o[1][1]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("creg b3", regf.o[1][0]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("dreg b0", regf.o[0][3]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("dreg b1", regf.o[0][2]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("dreg b2", regf.o[0][1]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("dreg b3", regf.o[0][0]) | |
# アナライズ | |
LogicAnalyzer.analyze do | |
clk.d = L | |
clrb.d = H | |
clrb.d = L | |
clrb.d = H | |
Fiber.yield | |
9.times do | |
clk.d = L | |
Fiber.yield | |
clk.d = H | |
Fiber.yield | |
end | |
:la | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment