diff --git a/lib/ADL/base.rb b/lib/ADL/base.rb index 4eb5910..f709fe9 100644 --- a/lib/ADL/base.rb +++ b/lib/ADL/base.rb @@ -27,7 +27,7 @@ def self.state end # reset state - def siminfra_reset_module_state; @@instructions = []; end + def siminfra_reset_module_state; @@instructions = []; @@operands = []; end # mixin for global counter, function returns 0,1,2,.... module GlobalCounter diff --git a/lib/ADL/builder.rb b/lib/ADL/builder.rb index 9c31471..0509888 100644 --- a/lib/ADL/builder.rb +++ b/lib/ADL/builder.rb @@ -29,7 +29,7 @@ def self.from_h(h) end # Basics -module SimInfra +module SimInfra def assert(condition, msg = nil); raise msg if !condition; end @@instructions = [] @@ -40,11 +40,13 @@ def self.interface_functions end class InstructionInfo - attr_accessor :name, :fields, :frmt, :map, :code, :map_code_blocks, :asm_str, :feature + attr_accessor :name, :fields, :frmt, :map, :code, :map_code_blocks, :asm_str, :feature, + :operand_map def initialize(name, feature) @name = name; @map_code_blocks = {} @feature = feature + @operand_map = {} end def to_h @@ -54,8 +56,8 @@ def to_h frmt: @frmt, asm_str: @asm_str, code: @code.to_h, - map: @map.to_h, - feature: @feature, + operand_map: @operand_map.transform_values(&:to_h), + operand_list: @operand_map.keys, } end @@ -66,24 +68,45 @@ def self.from_h(h) info.asm_str = h[:asm_str] info.code = Scope.new(nil) info.code.instance_variable_set(:@tree, h[:code][:tree].map { |s| IrStmt.from_h(s) }) - info.map = Scope.new(nil) - info.map.instance_variable_set(:@tree, h[:map][:tree].map { |s| IrStmt.from_h(s) }) + if h[:operand_map] + info.operand_map = h[:operand_map].transform_values { |v| Scope.from_h(v) } + end info end end + class OperandInfo + attr_accessor :name, :type, :regset, :map_proc + + def initialize(name, type = nil, regset = nil) + @name = name + @type = type + @regset = regset + @map_proc = nil + end + + def for(op_name) + info = OperandInfo.new(op_name, @type, @regset) + info.map_proc = @map_proc + info + end + + alias_method :[], :for + end + class InstructionInfoBuilder include SimInfra - def initialize(name, feature) - @info = InstructionInfo.new(name, feature) - @info.code = Scope.new(nil) + def initialize(name, feature) + @info = InstructionInfo.new(name, feature) + @info.code = Scope.new(nil) @@interface_functions.each do |func| + next if func[:kind] == :memory if !func[:return_types].empty? @info.code.instance_eval "def #{func[:name]}(*args) in_s = *args.map { |a| resolve_const(a) } - in_stmt = [tmpvar(#{func[:return_types][0]})] + in_stmt = [tmpvar(#{func[:return_types][0]})] in_stmt.concat(in_s) return stmt :#{func[:name]}, in_stmt end @@ -101,14 +124,9 @@ def initialize(name, feature) end def encoding(frmt, fields, *args) - @info.fields = fields - @info.frmt= frmt - map args - - sum_bits = 0 - for f in fields - sum_bits += Utility.get_type(f.value.type).bitsize - end + @info.fields = fields + @info.frmt= frmt + map args end attr_reader :info end @@ -122,17 +140,34 @@ def Instruction(name, &block) nil # only for debugging in IRB end + class OperandBuilder + include SimInfra + + def initialize(name, type = nil, regset = nil) + @info = OperandInfo.new(name, type, regset) + end + + attr_reader :info + end + + def Operand(name, type = nil, regset = nil, &block) + bldr = OperandBuilder.new(name, type, regset) + bldr.info.map_proc = block if block + bldr.info + end + + module_function :Operand + class InterfaceBuilder include SimInfra - def Function(name, output_types = [], input_types = []) - @@interface_functions << {:name => name, :return_types => output_types, :argument_types => input_types} + def Function(name, output_types = [], input_types = [], attrs = []) + @@interface_functions << {name: name, return_types: output_types, argument_types: input_types, attrs: attrs} end end def Interface(&blck) bldr = InterfaceBuilder.new() - bldr.instance_eval &blck end @@ -177,25 +212,25 @@ def self.from_h(h) @@regfiles = [] class RegisterFileBuilder - attr_reader :info - - def initialize(name) + attr_reader :info + + def initialize(name) @info = RegisterFileInfo.new(name) @info.regs = [] - end + end - def method_missing(name, *args) + def method_missing(name, *args) if name.to_s.start_with?('r') - size = name.to_s[1..].to_i - instance_eval "def #{name}(sym, *args); @info.regs << Register.new(sym, #{size}, args.size > 0 ? args : []); end", __FILE__, __LINE__ - @info.regs << Register.new(args[0], size, args.size > 1 ? args[1..] : []) + size = name.to_s[1..].to_i + instance_eval "def #{name}(sym, *args); @info.regs << Register.new(sym, #{size}, args.size > 0 ? args : []); end", __FILE__, __LINE__ + @info.regs << Register.new(args[0], size, args.size > 1 ? args[1..] : []) else - error "Unknown method #{name}" + error "Unknown method #{name}" + end end - end - def zero = :zero - def pc = :pc + def zero = :zero + def pc = :pc end def RegisterFile(name, &block) @@ -214,17 +249,13 @@ def RegFiles() module SimInfra class InstructionInfoBuilder def code(&block) - if !@info.map_code_blocks.empty? - @info.fields.each { |f| - @info.map.method(f.value.name, f.value.type) - } - end - @info.map_code_blocks.each do |k, v| - @info.map.instance_eval v[1] - end - @info.map_code_blocks.each do |k, v| - @info.code.method(k, v[0], @info.map.vars[k].regset) + # Link code scope methods to operand vars + @info.operand_map.each do |name, scope| + var = scope.vars[name] + @info.code.method(name, var.type, var.regset) if var end + + # Register files for regfile in @@regfiles for reg in regfile.regs @info.code.method(reg.name, ('r' + reg.size.to_s).to_sym) @@ -234,11 +265,32 @@ def code(&block) end def map(blocks) - if (!blocks.nil? && !blocks.empty?) - for blck in blocks - @info.map_code_blocks[blck[0]] = [blck[1], blck[2]] - end + return if blocks.nil? || blocks.empty? + + blocks.each do |block| + @info.operand_map[block.name] = build_scope(block) + end + end + + private + + def build_scope(block) + scope = Scope.new(nil) + @info.fields.each { |f| scope.method(f.value.name, f.value.type) } + op_name = block.name + value = if block.map_proc + scope.instance_eval(&block.map_proc) + elsif block.regset + scope.send("f_#{op_name}") + else + raise "operand '#{op_name}' has no map rule" + end + if block.regset + scope.arlet(op_name, block.regset, [:op], block.type, value) + else + scope.alet(op_name, [:op], block.type, value) end + scope end def asm(&block) diff --git a/lib/Target/RISC-V/32I.rb b/lib/Target/RISC-V/32I.rb index 95523dd..9867e56 100644 --- a/lib/Target/RISC-V/32I.rb +++ b/lib/Target/RISC-V/32I.rb @@ -158,19 +158,19 @@ module RV32I } Instruction(:slli) { - encoding *format_i_shift(0b0010011, 0b001, 0b00000) + encoding *format_i_shift(0b0010011, 0b001, 0b0000000) asm { "slli {rd}, {rs1}, {imm}" } code { rd[]= rs1 << imm } } Instruction(:srli) { - encoding *format_i_shift(0b0010011, 0b101, 0b00000) + encoding *format_i_shift(0b0010011, 0b101, 0b0000000) asm { "srli {rd}, {rs1}, {imm}" } code { rd[]= rs1 >> imm } } Instruction(:srai) { - encoding *format_i_shift(0b0010011, 0b101, 0b01000) + encoding *format_i_shift(0b0010011, 0b101, 0b0100000) asm { "srai {rd}, {rs1}, {imm}" } code { rd[]= rs1.s >> imm } } @@ -220,7 +220,7 @@ module RV32I Instruction(:jalr) { encoding *format_i(0b1100111, 0b000) asm { "jalr {rd}, {rs1}, {imm}" } - code { + code { let :t, :b32, pc + 4 branch((rs1 + imm) & (~1)) rd[]= t @@ -262,7 +262,7 @@ module RV32I asm { "lw {rd}, {imm}({rs1})" } code { rd[]= mem[rs1 + imm, :b32] } } - + Instruction(:lbu) { encoding *format_i(0b0000011, 0b100) asm { "lbu {rd}, {imm}({rs1})" } diff --git a/lib/Target/RISC-V/encoding.rb b/lib/Target/RISC-V/encoding.rb index 5ff0310..97fd69f 100644 --- a/lib/Target/RISC-V/encoding.rb +++ b/lib/Target/RISC-V/encoding.rb @@ -1,33 +1,29 @@ require_relative "../../ADL/base" +require_relative "../../ADL/builder" module SimInfra - def u_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, f_#{imm}.s << 12" - end + XReg = Operand(:XReg, :r32, :XRegs) - def i_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, f_#{imm}.s32" - end + IImm = Operand(:IImm, :s32) { f_imm.s32 } - def is_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, f_imm4_0" - end + UImm = Operand(:UImm, :s32) { f_imm.s32 << 12 } - def j_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, (f_imm20.b21 << 20 | f_imm19_12.b21 << 12 | f_imm11.b21 << 11 | f_imm10_1.b21 << 1).s32" - end + IsImm = Operand(:IsImm, :s32) { f_imm4_0 } - def b_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, (f_imm12.b13 << 12 | f_imm11.b13 << 11 | f_imm10_5.b13 << 5 | f_imm4_1.b13 << 1).s32" - end + JImm = Operand(:JImm, :s32) { + # imm[20] ← word[31], imm[19:12] ← word[19:12], imm[11] ← word[20], imm[10:1] ← word[30:21] + f_imm20.s32 << 20 | f_imm19_12.u32 << 12 | f_imm11.u32 << 11 | f_imm10_1.u32 << 1 + } - def s_imm(imm) - return imm, :s32, "let :#{imm}, [:op], :s32, (f_imm11_5.b12 << 5 | f_imm4_0.b12).s32" - end + BImm = Operand(:BImm, :s32) { + # imm[12] ← word[31], imm[11] ← word[7], imm[10:5] ← word[30:25], imm[4:1] ← word[11:8] + f_imm12.s32 << 12 | f_imm11.u32 << 11 | f_imm10_5.u32 << 5 | f_imm4_1.u32 << 1 + } - def xreg(name) - return name, :r32, "let :#{name}, :XRegs, [:op], :r32, f_#{name}" - end + SImm = Operand(:SImm, :s32) { + # imm[11:5] ← word[31:25], imm[4:0] ← word[11:7] + f_imm11_5.s32 << 5 | f_imm4_0.u32 + } end module SimInfra @@ -36,7 +32,7 @@ def format_u(opcode) field(:f_opcode, 6, 0, opcode), field(:f_rd, 11, 7), field(:f_imm, 31, 12), - ], xreg(:rd), u_imm(:imm) + ], XReg[:rd], UImm[:imm] end def format_r(opcode, funct3, funct7) @@ -47,7 +43,7 @@ def format_r(opcode, funct3, funct7) field(:f_rs1, 19, 15), field(:f_rs2, 24, 20), field(:f_funct7, 31, 25, funct7), - ], xreg(:rs2), xreg(:rs1), xreg(:rd) + ], XReg[:rs2], XReg[:rs1], XReg[:rd] end def format_i(opcode, funct3) @@ -57,19 +53,18 @@ def format_i(opcode, funct3) field(:f_funct3, 14, 12, funct3), field(:f_rs1, 19, 15), field(:f_imm, 31, 20), - ], i_imm(:imm), xreg(:rs1), xreg(:rd) + ], IImm[:imm], XReg[:rs1], XReg[:rd] end - def format_i_shift(opcode, func3, sopcode) - return :srai, [ + def format_i_shift(opcode, func3, funct7) + return :I, [ field(:f_opcode, 6, 0, opcode), - field(:func3, 14, 12, func3), - field(:f_imm4_0, 24, 20), field(:f_rd, 11, 7), + field(:f_funct3, 14, 12, func3), field(:f_rs1, 19, 15), - field(:f_temp, 26, 25, 0b01), - field(:f_sopcode, 31, 27, sopcode), - ], is_imm(:imm), xreg(:rs1), xreg(:rd) + field(:f_imm11_5, 31, 25, funct7), + field(:f_imm4_0, 24, 20), + ], IsImm[:imm], XReg[:rs1], XReg[:rd] end def format_b(opcode, funct3) @@ -78,32 +73,32 @@ def format_b(opcode, funct3) field(:f_funct3, 14, 12, funct3), field(:f_rs1, 19, 15), field(:f_rs2, 24, 20), - field(:f_imm4_1, 11, 8), - field(:f_imm10_5, 30, 25), - field(:f_imm11, 7, 7), - field(:f_imm12, 31, 31), - ], b_imm(:imm), xreg(:rs1), xreg(:rs2) + field(:f_imm4_1, 11, 8), # → imm[4:1] + field(:f_imm10_5, 30, 25), # → imm[10:5] + field(:f_imm11, 7, 7), # → imm[11] + field(:f_imm12, 31, 31), # → imm[12] + ], BImm[:imm], XReg[:rs1], XReg[:rs2] end def format_j(opcode) return :J, [ field(:f_opcode, 6, 0, opcode), field(:f_rd, 11, 7), - field(:f_imm20, 31, 31), - field(:f_imm19_12, 19, 12), - field(:f_imm11, 20, 20), - field(:f_imm10_1, 30, 21), - ], j_imm(:imm), xreg(:rd) + field(:f_imm20, 31, 31), # → imm[20] + field(:f_imm19_12, 19, 12), # → imm[19:12] + field(:f_imm11, 20, 20), # → imm[11] + field(:f_imm10_1, 30, 21), # → imm[10:1] + ], JImm[:imm], XReg[:rd] end def format_s(opcode, func3) return :S, [ field(:f_opcode, 6, 0, opcode), - field(:func3, 14, 12, func3), - field(:f_imm4_0, 11, 7), + field(:f_func3, 14, 12, func3), + field(:f_imm4_0, 11, 7), # → imm[4:0] field(:f_rs1, 19, 15), field(:f_rs2, 24, 20), - field(:f_imm11_5, 31, 25), - ], s_imm(:imm), xreg(:rs1), xreg(:rs2) + field(:f_imm11_5, 31, 25), # → imm[11:5] + ], SImm[:imm], XReg[:rs1], XReg[:rs2] end end diff --git a/sim_gen/Decoders/decoder.rb b/sim_gen/Decoders/decoder.rb index c9475d0..e8c28f9 100644 --- a/sim_gen/Decoders/decoder.rb +++ b/sim_gen/Decoders/decoder.rb @@ -157,12 +157,8 @@ def make_child_tree(node_value, separ_mask, instructions, subtree) def map_operands(insn) operands = {} - cnt = 0 - for node in insn[:map][:tree] - if node[:name] == :new_var && !node[:attrs].nil? && node[:attrs].include?(:op) - operands[node[:oprnds][0][:name]] = "insn.operand#{cnt}" - cnt += 1 - end + (insn[:operand_list] || []).each_with_index do |name, idx| + operands[name] = "insn.operand#{idx}" end operands end @@ -189,8 +185,8 @@ def generate_mapping_body(insn) emitter = Utility::GenEmitter.new operand_map = map_operands(insn) gen = CodeGen::CppGenerator.new(emitter, operand_map) - for node in insn[:map][:tree] - gen.generate_statement(node) + (insn[:operand_map] || {}).each_value do |scope| + (scope[:tree] || []).each { |node| gen.generate_statement(node) } end emitter end diff --git a/sim_gen/ExecEngines/naive_interpreter.rb b/sim_gen/ExecEngines/naive_interpreter.rb index ae00151..7aff60a 100644 --- a/sim_gen/ExecEngines/naive_interpreter.rb +++ b/sim_gen/ExecEngines/naive_interpreter.rb @@ -33,12 +33,8 @@ module TranslationUnit def map_operands(insn) operands = {} - cnt = 0 - insn[:map][:tree].each do |node| - if node[:name] == :new_var && !node[:attrs].nil? && node[:attrs].include?(:op) - operands[node[:oprnds][0][:name]] = "insn.operand#{cnt}" - cnt += 1 - end + (insn[:operand_list] || []).each_with_index do |name, idx| + operands[name] = "insn.operand#{idx}" end operands[:pc] = 'cpu.getPC()' operands diff --git a/sim_gen/ISA/isa.rb b/sim_gen/ISA/isa.rb index 4f4b830..e50683f 100644 --- a/sim_gen/ISA/isa.rb +++ b/sim_gen/ISA/isa.rb @@ -18,14 +18,20 @@ def find_max_operands(instructions) max_operands = 0 max_size = 0 instructions.each do |insn| - operands_count = 0 - insn[:map][:tree].each do |node| - if node[:name] == :new_var && !node[:attrs].nil? && node[:attrs].include?(:op) - operands_count += 1 - max_size = Utility.get_type(node[:oprnds][0][:type]).bitsize if Utility.get_type(node[:oprnds][0][:type]).bitsize > max_size - end - end - max_operands = operands_count if operands_count > max_operands + op_list = insn[:operand_list] || [] + max_operands = op_list.size if op_list.size > max_operands + op_map = insn[:operand_map] || {} + op_list.each do |name| + scope = op_map[name] + next unless scope + new_var_node = (scope[:tree] || []).find { |n| + n[:name] == :new_var && n[:attrs]&.include?(:op) + } + next unless new_var_node + type = new_var_node[:oprnds][0][:type] + bitsize = Utility.get_type(type).bitsize + max_size = bitsize if bitsize > max_size + end end [max_operands, max_size] end