-
-
Save mirichi/d1893d89936e1c989b30bc386851bf04 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_relative './hsim' | |
require_relative './riscvasm' | |
def _if(cond, t, f) | |
raise "size error" if t.size != f.size | |
mux = Mux1_n.new(t.size) | |
mux.s = cond | |
mux.d = [t, f] | |
mux.o | |
end | |
def _equal(a, b) | |
raize "size error" if a.size != b.size | |
ary = [] | |
a.zip(b) do |p1, p2| | |
ary << (p1 ^ p2) | |
end | |
return ~ary.inject(ary.pop){|memo, item|memo | item} | |
end | |
def _to_pin(i, h, l) | |
i.to_s.each_byte.map{|s|(s-0x30) == 1 ? h : l} | |
end | |
# 電源とグランド | |
_vcc = Line.new | |
_gnd = Line.new | |
vcc = _vcc.o | |
gnd = _gnd.o | |
# クロックとクリアの入力線 | |
clk = Line.new | |
clrb = Line.new | |
# 32bitデータバス | |
bus = Bus.new(32) | |
# ROM | |
rom = ROM.new(3, 32) # アドレス線3本、データ線32本 | |
# 8アドレスぶんの命令 | |
rom.d = RISCVASM.asm do | |
addi r1, r0, 0 | |
addi r2, r0, 0 | |
addi r3, r0, 1 | |
label :fibonacci | |
add r1, r0, r2 | |
add r2, r0, r3 | |
add r3, r1, r2 | |
jal r0, :fibonacci | |
nop | |
end.map{|t|_to_pin(t, vcc, gnd)}.reverse | |
## 命令デコーダ(RISC-V/RV32I) | |
insn = bus.o | |
insn_bit_funct7 = insn[0..6] | |
insn_bit_imm11_5 = insn[0..6] | |
insn_bit_imm11_0 = insn[0..11] | |
insn_bit_imm20_1 = [insn[0]] + insn[12..19] + [insn[11]] + insn[1..10] | |
insn_bit_rs2 = insn[7..11] | |
insn_bit_rs1 = insn[12..16] | |
insn_bit_funct3 = insn[17..19] | |
insn_bit_rd = insn[20..24] | |
insn_bit_opcode = insn[25..31] | |
# デコード用ビットパターン | |
opcode_addi = _to_pin("0010011", vcc, gnd) | |
opcode_add = _to_pin("0110011", vcc, gnd) | |
opcode_jalr = _to_pin("1100111", vcc, gnd) | |
opcode_jal = _to_pin("1101111", vcc, gnd) | |
funct3_addi = _to_pin("000" , vcc, gnd) | |
funct3_add = _to_pin("000" , vcc, gnd) | |
funct3_jalr = _to_pin("000" , vcc, gnd) | |
funct7_add = _to_pin("0000000", vcc, gnd) | |
# ADDI命令でH | |
insn_addi = _equal(insn_bit_opcode, opcode_addi) & _equal(insn_bit_funct3, funct3_addi) | |
# ADD命令でH | |
insn_add = _equal(insn_bit_opcode, opcode_add) & _equal(insn_bit_funct3, funct3_add) & _equal(insn_bit_funct7, funct7_add) | |
# JALR命令でH | |
insn_jalr = _equal(insn_bit_opcode, opcode_jalr) & _equal(insn_bit_funct3, funct3_jalr) | |
# JAL命令でH | |
insn_jal = _equal(insn_bit_opcode, opcode_jal) | |
# レジスタ書き込み条件 | |
write_reg = insn_addi | insn_add | insn_jalr | insn_jal | |
## 各種回路ブロック生成 | |
# 32bitプログラムカウンタ用レジスタ | |
pc = Register.new(32) | |
pc.clk = clk.o | |
pc.clrb = clrb.o | |
pc.w = vcc | |
# 30bitインクリメンタ | |
inc = Incrementer.new(30) | |
# レジスタファイル(32bitが32個) | |
regf = RegisterFile.new(5, 32) | |
regf.clk = clk.o | |
regf.clrb = clrb.o | |
# 32bit加算器 | |
adder = Adder.new(32) | |
## 回路接続 | |
# ROMの出力はThreeStateBufferなのでBusオブジェクトにaddする | |
bus.add rom.o | |
# ROMの出力の値はBusオブジェクトから取り出す | |
# pcとインクリメンタ接続 | |
pc.d = _if(insn_jalr | insn_jal, adder.o, inc.o + [gnd, gnd]) | |
inc.d = pc.o[0, 30] | |
# ROMにPCを接続 | |
rom.a = pc.o[27, 3] | |
rom.csb = gnd | |
# レジスタファイルの入力ポート接続 | |
regf.d = _if(insn_jalr | insn_jal, inc.o + [gnd, gnd], adder.o) | |
regf.sin = insn_bit_rd | |
regf.w = write_reg # レジスタ書き込み条件 | |
# レジスタファイルの出力ポート選択信号の接続 | |
regf.sout0 = insn_bit_rs1 | |
regf.sout1 = insn_bit_rs2 | |
# 32bit全加算器 | |
adder.d = [_if(insn_jal, pc.o, regf.o0), _if(insn_jal, [insn_bit_imm20_1[0]]*11 + insn_bit_imm20_1 + [gnd], # jal命令 | |
_if(insn_add, regf.o1, # add命令 | |
[insn_bit_imm11_0[0]]*20 + insn_bit_imm11_0 # それ以外 | |
)) | |
] | |
adder.x = gnd | |
# 電源接続 | |
_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("insn addi", insn_addi) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("insn add", insn_add) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("insn jal", insn_jal) | |
#LogicAnalyzer::probes << LogicAnalyzer::Probe.new("opcode b0", bus.o[31]) | |
#LogicAnalyzer::probes << LogicAnalyzer::Probe.new("opcode b1", bus.o[30]) | |
#LogicAnalyzer::probes << LogicAnalyzer::Probe.new("opcode b2", bus.o[29]) | |
#LogicAnalyzer::probes << LogicAnalyzer::Probe.new("opcode b3", bus.o[28]) | |
#LogicAnalyzer::probes << LogicAnalyzer::Probe.new("opcode b4", bus.o[27]) | |
#LogicAnalyzer::probes << LogicAnalyzer::Probe.new("opcode b5", bus.o[26]) | |
#LogicAnalyzer::probes << LogicAnalyzer::Probe.new("opcode b6", bus.o[25]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b0", pc.o[31]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b1", pc.o[30]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b2", pc.o[29]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b3", pc.o[28]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("adr b4", pc.o[27]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b0", regf.o[30][31]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b1", regf.o[30][30]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b2", regf.o[30][29]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b3", regf.o[30][28]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b4", regf.o[30][27]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b5", regf.o[30][26]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b6", regf.o[30][25]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b6", regf.o[30][24]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b6", regf.o[30][23]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b6", regf.o[30][22]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b6", regf.o[30][21]) | |
LogicAnalyzer::probes << LogicAnalyzer::Probe.new("r1 b6", regf.o[30][20]) | |
# アナライズ | |
LogicAnalyzer.analyze do | |
clk.d = L | |
clrb.d = H | |
clrb.d = L | |
clrb.d = H | |
Fiber.yield | |
60.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