-
-
Save mirichi/abf4427ee536c900cfb03e4d434b26d1 to your computer and use it in GitHub Desktop.
lb命令実装
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' | |
# 外付けRAM | |
class RAM | |
attr_reader :memory | |
def initialize(a, d) | |
@memory = Array.new(80*30){0} | |
@o = Array.new(d){OutputPin.new} | |
@o.each{|t|t.set(false)} | |
end | |
def clk=(v) | |
v.output_objects << self | |
@clk = v | |
end | |
def a=(v) | |
@addr = v | |
end | |
def d=(v) | |
@data = v | |
end | |
def w=(v) | |
@w = v # HがWrite有効 | |
end | |
def r=(v) | |
@r = v # HがRead有効 | |
end | |
def o | |
@o | |
end | |
def update | |
# クロックがHになったら処理する | |
if @clk.get | |
address = ("0b" + @addr.map{|o|o.get ? "1" : "0"}.join).to_i(2) | |
if @w.get # RAMへの書き込み | |
data = ("0b" + @data.map{|o|o.get ? "1" : "0"}.join).to_i(2) | |
@memory[address] = data | |
end | |
if @r.get # RAMからの読み込み | |
memory = @memory[address].to_s(2).rjust(@o.size, "0") | |
@o.each.with_index do |t, i| | |
t.set(memory[i] == "1") | |
end | |
end | |
end | |
end | |
end | |
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(5, 32) # アドレス線5本、データ線32本 | |
# 32アドレスぶんの命令 | |
rom.d = RISCVASM.asm do | |
addi r2, r0, 72 | |
sb r2, 0, r0 | |
addi r2, r0, 101 | |
sb r2, 1, r0 | |
addi r2, r0, 108 | |
sb r2, 2, r0 | |
addi r2, r0, 108 | |
sb r2, 3, r0 | |
addi r2, r0, 111 | |
sb r2, 4, r0 | |
addi r2, r0, 32 | |
sb r2, 5, r0 | |
addi r2, r0, 119 | |
sb r2, 6, r0 | |
addi r2, r0, 111 | |
sb r2, 7, r0 | |
addi r2, r0, 114 | |
sb r2, 8, r0 | |
addi r2, r0, 108 | |
sb r2, 9, r0 | |
addi r2, r0, 100 | |
sb r2, 10, r0 | |
addi r2, r0, 33 | |
sb r2, 11, r0 | |
lb r2, 0, r0 | |
sb r2, 80, r0 | |
lb r2, 1, r0 | |
sb r2, 81, r0 | |
lb r2, 2, r0 | |
sb r2, 82, r0 | |
lb r2, 3, r0 | |
sb r2, 83, r0 | |
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_imm4_0 = insn[20..24] | |
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] | |
# 即値 | |
imm_J_Type = [insn_bit_imm20_1[0]]*11 + insn_bit_imm20_1 + [gnd] | |
imm_I_Type = [insn_bit_imm11_0[0]]*20 + insn_bit_imm11_0 | |
imm_S_Type = [insn_bit_imm11_5[0]]*20 + insn_bit_imm11_5 + insn_bit_imm4_0 | |
# デコード用ビットパターン | |
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) | |
opcode_sb = _to_pin("0100011", vcc, gnd) | |
opcode_lb = _to_pin("0000011", vcc, gnd) | |
funct3_addi = _to_pin("000" , vcc, gnd) | |
funct3_add = _to_pin("000" , vcc, gnd) | |
funct3_jalr = _to_pin("000" , vcc, gnd) | |
funct3_sb = _to_pin("000" , vcc, gnd) | |
funct3_lb = _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) | |
# sb命令でH | |
insn_sb = _equal(insn_bit_opcode, opcode_sb) | |
# lb命令でH | |
insn_lb = _equal(insn_bit_opcode, opcode_lb) | |
# レジスタ書き込み条件 | |
write_reg = insn_addi | insn_add | insn_jalr | insn_jal | insn_lb | |
## 各種回路ブロック生成 | |
# 32bitプログラムカウンタ用レジスタ | |
pc = Register.new(32) | |
pc.clk = clk.o | |
pc.clrb = clrb.o | |
# 30bitインクリメンタ | |
inc = Incrementer.new(30) | |
# レジスタファイル(32bitが32個) | |
regf = RegisterFile.new(5, 32) | |
regf.clk = clk.o | |
regf.clrb = clrb.o | |
rs1 = regf.o0 | |
rs2 = regf.o1 | |
# 32bit加算器 | |
adder = Adder.new(32) | |
# 回路停止用1bitレジスタ(Hの時に停止) | |
stall = Register.new(1) | |
stall.clk = clk.o | |
stall.clrb = clrb.o | |
stall.w = vcc | |
st = ~stall.o[0] & insn_lb # 実行状態かつlb命令のときにHになる(次のクロックですぐLに戻る) | |
stall.d = [st] | |
# でっちあげRAM | |
ram = RAM.new(8, 8) | |
ram.a = adder.o[24..31] | |
ram.d = [gnd]*24 + rs2[24..31] | |
ram.clk = clk.o | |
ram.w = insn_sb | |
ram.r = st | |
## 回路接続 | |
# 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] | |
# pcの書き込み条件 | |
pc.w = ~st | |
# ROMにPCを接続 | |
rom.a = pc.o[25, 5] | |
rom.csb = gnd | |
# レジスタファイルの入力ポート接続 | |
regf.d = _if(insn_jalr | insn_jal, inc.o + [gnd, gnd], # jalr or jalの場合はrdに戻りアドレスを格納する | |
_if(insn_lb, [gnd]*24 + ram.o, # lb命令の場合はramの出力 | |
adder.o # それ以外の命令は加算器の結果を格納する | |
)) | |
regf.sin = insn_bit_rd # 書き込むレジスタはRISC-Vの場合は必ずrdになる | |
regf.w = write_reg & ~st # レジスタ書き込み条件 | |
# レジスタファイルの出力ポート選択信号の接続 | |
regf.sout0 = insn_bit_rs1 | |
regf.sout1 = insn_bit_rs2 | |
# 32bit全加算器 | |
adder.d = [_if(insn_jal, pc.o, # jal命令 | |
rs1 # それ以外 | |
), | |
_if(insn_jal, imm_J_Type, # jal命令 | |
_if(insn_add, rs2, # add命令 | |
_if(insn_sb, imm_S_Type, # sb命令 | |
imm_I_Type # それ以外 | |
))) | |
] | |
adder.x = gnd | |
# 電源接続 | |
_vcc.d = H | |
_gnd.d = L | |
# 簡易テキストVRAM | |
require 'dxruby' | |
clk.d = L | |
clrb.d = H | |
clrb.d = L | |
clrb.d = H | |
36.times do | |
clk.d = L | |
clk.d = H | |
end | |
font = Font.new(16, "MS ゴシック") | |
Window.loop do | |
30.times do |y| | |
80.times do |x| | |
Window.draw_font(x*8, y*16, ram.memory[x+y*80].chr(Encoding::WINDOWS_31J), font) | |
end | |
end | |
break if Input.key_push?(K_ESCAPE) | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment