Skip to content

Instantly share code, notes, and snippets.

@mirichi

mirichi/riscvasm.rb Secret

Created Jan 5, 2018
Embed
What would you like to do?
risc-vアセンブラ
module RISCVASM
# 32bitレジスタ
class Register32
end
# 32bitレジスタ定義
class X0 < Register32;def bit;'00000';end;end
class X1 < Register32;def bit;'00001';end;end
class X2 < Register32;def bit;'00010';end;end
class X3 < Register32;def bit;'00011';end;end
class X4 < Register32;def bit;'00100';end;end
class X5 < Register32;def bit;'00101';end;end
class X6 < Register32;def bit;'00110';end;end
class X7 < Register32;def bit;'00111';end;end
class X8 < Register32;def bit;'01000';end;end
class X9 < Register32;def bit;'01001';end;end
class X10 < Register32;def bit;'01010';end;end
class X11 < Register32;def bit;'01011';end;end
class X12 < Register32;def bit;'01100';end;end
class X13 < Register32;def bit;'01101';end;end
class X14 < Register32;def bit;'01110';end;end
class X15 < Register32;def bit;'01111';end;end
class X16 < Register32;def bit;'10000';end;end
class X17 < Register32;def bit;'10001';end;end
class X18 < Register32;def bit;'10010';end;end
class X19 < Register32;def bit;'10011';end;end
class X20 < Register32;def bit;'10100';end;end
class X21 < Register32;def bit;'10101';end;end
class X22 < Register32;def bit;'10110';end;end
class X23 < Register32;def bit;'10111';end;end
class X24 < Register32;def bit;'11000';end;end
class X25 < Register32;def bit;'11001';end;end
class X26 < Register32;def bit;'11010';end;end
class X27 < Register32;def bit;'11011';end;end
class X28 < Register32;def bit;'11100';end;end
class X29 < Register32;def bit;'11101';end;end
class X30 < Register32;def bit;'11110';end;end
class X31 < Register32;def bit;'11111';end;end
# アセンブラクラス
class Assembler
attr_reader :buf, :labels
def initialize
@buf = []
@labels = {}
@reserve = {}
end
def x0;X0.new;end
def x1;X1.new;end
def x2;X2.new;end
def x3;X3.new;end
def x4;X4.new;end
def x5;X5.new;end
def x6;X6.new;end
def x7;X7.new;end
def x8;X8.new;end
def x9;X9.new;end
def x10;X10.new;end
def x11;X11.new;end
def x12;X12.new;end
def x13;X13.new;end
def x14;X14.new;end
def x15;X15.new;end
def x16;X16.new;end
def x17;X17.new;end
def x18;X18.new;end
def x19;X19.new;end
def x20;X20.new;end
def x21;X21.new;end
def x22;X22.new;end
def x23;X23.new;end
def x24;X24.new;end
def x25;X25.new;end
def x26;X26.new;end
def x27;X27.new;end
def x28;X28.new;end
def x29;X29.new;end
def x30;X30.new;end
def x31;X31.new;end
class Insn < Struct.new(:type, :opcode, :funct3, :funct7, :rd, :rs1, :rs2, :imm);end
def label(name)
raise if @labels.has_key?(name.to_s)
@labels[name.to_s] = @buf.size
end
def nop
self.addi(x0, x0, 0)
end
def li(rd, imm)
if Register32 === rd and Integer === imm
self.lui(rd, imm >> 12)
self.ori(rd, rd, imm & 0xfff)
else
raise
end
end
def mv(rd, rs)
if Register32 === rd and Register32 === rs
self.addi(rd, rs, 0)
else
raise
end
end
def lui(rd, imm)
if Register32 === rd and Integer === imm
@buf << Insn.new(:U, '0110111', nil, nil, rd, nil, nil, imm)
else
raise
end
end
def auipc(rd, imm)
if Register32 === rd and Integer === imm
@buf << Insn.new(:U, '0010111', nil, nil, rd, nil, nil, imm)
else
raise
end
end
def jal(rd, imm)
if Register32 === rd and (Integer === imm or String === imm or Symbol === imm)
@buf << Insn.new(:J, '1101111', nil, nil, rd, nil, nil, imm)
else
raise
end
end
def jalr(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '1100111', '000', nil, rd, rs, nil, imm)
else
raise
end
end
def addi(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '000', nil, rd, rs, nil, imm)
else
raise
end
end
def add(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '000', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def sub(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '000', '0100000', rd, rs1, rs2, nil)
else
raise
end
end
def andi(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '111', nil, rd, rs, nil, imm)
else
raise
end
end
def _and(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '111', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def ori(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '110', nil, rd, rs, nil, imm)
else
raise
end
end
def _or(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '110', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def xori(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '100', nil, rd, rs, nil, imm)
else
raise
end
end
def _xor(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '100', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def slli(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '001', nil, rd, rs, nil, imm)
else
raise
end
end
def sll(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '001', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def srli(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '101', nil, rd, rs, nil, imm)
else
raise
end
end
def srl(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '101', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def srai(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '101', nil, rd, rs, nil, imm)
else
raise
end
end
def sra(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '101', '0100000', rd, rs1, rs2, nil)
else
raise
end
end
def slti(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '010', nil, rd, rs, nil, imm)
else
raise
end
end
def slt(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '010', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def sltui(rd, rs, imm)
if Register32 === rd and Register32 === rs and Integer === imm
@buf << Insn.new(:I, '0010011', '011', nil, rd, rs, nil, imm)
else
raise
end
end
def sltu(rd, rs1, rs2)
if Register32 === rd and Register32 === rs1 and Register32 === rs2
@buf << Insn.new(:R, '0110011', '011', '0000000', rd, rs1, rs2, nil)
else
raise
end
end
def sb(rs2, imm, rs1)
if Register32 === rs1 and Register32 === rs2 and Integer === imm
@buf << Insn.new(:S, '0100011', '000', nil, nil, rs1, rs2, imm)
else
raise
end
end
def sh(rs2, imm, rs1)
if Register32 === rs1 and Register32 === rs2 and Integer === imm
@buf << Insn.new(:S, '0100011', '001', nil, nil, rs1, rs2, imm)
else
raise
end
end
def sw(rs2, imm, rs1)
if Register32 === rs1 and Register32 === rs2 and Integer === imm
@buf << Insn.new(:S, '0100011', '010', nil, nil, rs1, rs2, imm)
else
raise
end
end
def lb(rd, imm, rs1)
if Register32 === rd and Register32 === rs1 and Integer === imm
@buf << Insn.new(:I, '0000011', '000', nil, rd, rs1, nil, imm)
else
raise
end
end
def lh(rd, imm, rs1)
if Register32 === rd and Register32 === rs1 and Integer === imm
@buf << Insn.new(:I, '0000011', '001', nil, rd, rs1, nil, imm)
else
raise
end
end
def lw(rd, imm, rs1)
if Register32 === rd and Register32 === rs1 and Integer === imm
@buf << Insn.new(:I, '0000011', '010', nil, rd, rs1, nil, imm)
else
raise
end
end
def lbu(rd, imm, rs1)
if Register32 === rd and Register32 === rs1 and Integer === imm
@buf << Insn.new(:I, '0000011', '100', nil, rd, rs1, nil, imm)
else
raise
end
end
def lhu(rd, imm, rs1)
if Register32 === rd and Register32 === rs1 and Integer === imm
@buf << Insn.new(:I, '0000011', '101', nil, rd, rs1, nil, imm)
else
raise
end
end
def beq(rs1, rs2, imm)
if Register32 === rs1 and Register32 === rs2 and (Integer === imm or String === imm or Symbol === imm)
@buf << Insn.new(:B, '1100011', '000', nil, nil, rs1, rs2, imm)
else
raise
end
end
def bne(rs1, rs2, imm)
if Register32 === rs1 and Register32 === rs2 and (Integer === imm or String === imm or Symbol === imm)
@buf << Insn.new(:B, '1100011', '001', nil, nil, rs1, rs2, imm)
else
raise
end
end
def blt(rs1, rs2, imm)
if Register32 === rs1 and Register32 === rs2 and (Integer === imm or String === imm or Symbol === imm)
@buf << Insn.new(:B, '1100011', '100', nil, nil, rs1, rs2, imm)
else
raise
end
end
def bge(rs1, rs2, imm)
if Register32 === rs1 and Register32 === rs2 and (Integer === imm or String === imm or Symbol === imm)
@buf << Insn.new(:B, '1100011', '101', nil, nil, rs1, rs2, imm)
else
raise
end
end
def bltu(rs1, rs2, imm)
if Register32 === rs1 and Register32 === rs2 and (Integer === imm or String === imm or Symbol === imm)
@buf << Insn.new(:B, '1100011', '110', nil, nil, rs1, rs2, imm)
else
raise
end
end
def bgeu(rs1, rs2, imm)
if Register32 === rs1 and Register32 === rs2 and (Integer === imm or String === imm or Symbol === imm)
@buf << Insn.new(:B, '1100011', '111', nil, nil, rs1, rs2, imm)
else
raise
end
end
end
def self.asm(datasize, &b)
tmp = Assembler.new
tmp.instance_eval &b
result = tmp.buf.map.with_index do |insn, i|
case insn.type
when :R
insn.funct7 + insn.rs2.bit + insn.rs1.bit + insn.funct3 + insn.rd.bit + insn.opcode
when :R2
insn.funct7 + insn.rs2.to_s(2).rjust(5,"0") + insn.rs1.bit + insn.funct3 + insn.rd.bit + insn.opcode
when :I
format("%.14b", insn.imm)[2..-1] + insn.rs1.bit + insn.funct3 + insn.rd.bit + insn.opcode
when :S
imm = format("%.14b", insn.imm)[2..-1]
imm[0..6] + insn.rs2.bit + insn.rs1.bit + insn.funct3 + imm[7..11] + insn.opcode
when :B
imm = if Integer === insn.imm
#[12][10:5] [4:1][11]
format("%.14b", insn.imm / 2)[2..-1]
else
format("%.14b", (tmp.labels[insn.imm.to_s] - i) * 2)[2..-1]
end
imm[0] + imm[2..7] + insn.rs2.bit + insn.rs1.bit + insn.funct3 + imm[8..11] + imm[1] + insn.opcode
when :U
#[31:12]
addr = if Integer === insn.imm
format("%.22b", insn.imm)[-20..-1]
end
addr + insn.rd.bit + insn.opcode
when :J
#[20][10:1][11][19:12]
addr = if Integer === insn.imm
format("%.22b", insn.imm / 2)[2..-1]
else
format("%.22b", (tmp.labels[insn.imm.to_s] - i) * 2)[2..-1]
end
addr[0] + addr[10..19] + addr[9] + addr[1..8] + insn.rd.bit + insn.opcode
end
end
if datasize > result.size
result.concat(['00000000000000000000000000010011']*(datasize - result.size))
end
return result
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment