-
-
Save mirichi/41f73dab95db1541cb9e 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
require './hsim' | |
# 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 | |
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 | |
# 電源とグランド | |
_vcc = Line.new | |
_gnd = Line.new | |
vcc = _vcc.o | |
gnd = _gnd.o | |
# クロックとクリアの入力線 | |
clk = Line.new | |
clrb = Line.new | |
# 8bitデータバス | |
bus = Bus.new(8) | |
# ROM | |
rom = ROM.new(3, 8) # アドレス線3本、データ線8本 | |
rom.d = [ # 8アドレスぶんのデータ | |
[gnd, gnd, gnd, gnd, gnd, gnd, gnd, gnd], # 0 : mov a, 0x0 | |
[gnd, gnd, gnd, gnd, gnd, vcc, gnd, vcc], # 1 : mov b, 0x1 | |
[vcc, gnd, gnd, gnd, gnd, gnd, vcc, gnd], # 2 : mov c, a | |
[vcc, gnd, gnd, vcc, gnd, vcc, vcc, gnd], # 3 : add c, b | |
[vcc, gnd, gnd, gnd, gnd, vcc, gnd, gnd], # 4 : mov a, b | |
[vcc, gnd, gnd, gnd, vcc, gnd, gnd, vcc], # 5 : mov b, c | |
[gnd, vcc, gnd, gnd, gnd, gnd, gnd, gnd], # 6 : add a, 0 | |
[vcc, vcc, gnd, gnd, gnd, gnd, vcc, gnd], # 7 : jnc 2 | |
].reverse | |
#0 0 imm3 imm2 imm1 imm0 reg1 reg0 : mov reg, imm | |
#0 1 imm3 imm2 imm1 imm0 reg1 reg0 : add reg, imm | |
#1 0 X 0 rs1 rs0 rd1 rd0 : mov rd, rs | |
#1 0 X 1 rs1 rs0 rd1 rd0 : add rd, rs | |
#1 1 adr5 adr4 adr3 adr2 adr1 adr0 : jnc adr | |
## 命令デコーダ | |
# mov命令時にH | |
insn_mov = (~bus.o[0] & ~bus.o[1]) | (bus.o[0] & ~bus.o[1] & ~bus.o[3]) | |
# add命令時にH | |
insn_add = (~bus.o[0] & bus.o[1]) | (bus.o[0] & ~bus.o[1] & bus.o[3]) | |
# ジャンプ命令時にH | |
insn_jnc = bus.o[0] & bus.o[1] | |
# レジスタ書き込み条件 | |
write_reg = ~insn_jnc | |
# ソースがイミディエート時にH | |
source_imm = ~bus.o[0] | |
# ソースがレジスタ時にH | |
source_reg = bus.o[0] & ~bus.o[1] | |
## 各種回路ブロック生成 | |
# キャリーフラグ用1bitレジスタ | |
cf = Register.new(1) | |
cf.clk = clk.o | |
cf.clrb = clrb.o | |
cf.w = vcc | |
# 4bitプログラムカウンタ用レジスタ | |
pc = Register.new(4) | |
pc.clk = clk.o | |
pc.clrb = clrb.o | |
pc.w = vcc | |
# 4bitインクリメンタ | |
inc = Incrementer.new(4) | |
# ジャンプ命令用のマルチプレクサ | |
muxj = Mux1_n.new(4) # 命令中には7ビットのアドレスがあるが、この回路のアドレス線は4本しかない | |
# レジスタファイル | |
regf = RegisterFile.new(2, 4) | |
regf.clk = clk.o | |
regf.clrb = clrb.o | |
# 加算器 | |
adder = Adder.new(4) | |
# 書き込みデータ選択用マルチプレクサ | |
muxd = Mux1_n.new(4) | |
# 出力ポート1とバスの入力を選択するマルチプレクサ | |
muxa = Mux1_n.new(4) | |
## 回路接続 | |
# ROMの出力はThreeStateBufferなのでBusオブジェクトにaddする | |
bus.add rom.o | |
# ROMの出力の値はBusオブジェクトから取り出す | |
# pcとインクリメンタ接続 | |
pc.d = muxj.o | |
inc.d = pc.o | |
# ジャンプ命令でキャリーフラグがLの場合に命令内のアドレスを使う(jncなので) | |
muxj.d = [bus.o[4..7], inc.o] | |
muxj.s = insn_jnc & ~cf.o[0] | |
# ROMにカウンタの値を接続 | |
rom.a = pc.o[1..3] | |
rom.csb = pc.o[0] | |
# 入力ポートの接続 | |
regf.d = muxd.o | |
regf.sin = bus.o[6..7] # 命令的に出力と同じレジスタが選択される | |
regf.w = write_reg # レジスタ書き込み条件 | |
# 出力ポート選択信号の接続 | |
regf.sout0 = bus.o[6..7] | |
regf.sout1 = bus.o[4..5] | |
muxa.d = [bus.o[2..5], regf.o1] | |
muxa.s = source_imm # ソースがイミディエートの場合、命令内の値を使う | |
# 4bit全加算器 | |
adder.d = [regf.o0, muxa.o] # レジスタファイルの出力ポート0とmuxaのデータを加算する | |
adder.x = gnd # キャリー入力は今のところ使わないのでL固定としておく | |
# movとaddの命令によってmuxaか加算器を通した値かを選択するマルチプレクサ | |
muxd.d = [adder.o, muxa.o] | |
muxd.s = insn_add | |
# 全加算器のキャリー出力をキャリーフラグに入力する | |
cf.d = [adder.c] | |
# 電源接続 | |
_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 | |
w = (640 - x) / buf.size | |
# 画像作成 | |
@@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 * w + x, i * size + 8, j * w + x, i * size + size - 1, C_WHITE) | |
end | |
image.line(j * w + x, i * size + (b[i] ? 8 : size - 1), j * w + x + w, 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("d b7", bus.o[0]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b0", pc.o[3]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b1", pc.o[2]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b2", pc.o[1]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b3", pc.o[0]) | |
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.analyze do | |
clk.d = L | |
clrb.d = H | |
clrb.d = L | |
clrb.d = H | |
Fiber.yield | |
40.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