1b1994897Sopenharmony_ci# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 2b1994897Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 3b1994897Sopenharmony_ci# you may not use this file except in compliance with the License. 4b1994897Sopenharmony_ci# You may obtain a copy of the License at 5b1994897Sopenharmony_ci# 6b1994897Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 7b1994897Sopenharmony_ci# 8b1994897Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 9b1994897Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 10b1994897Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11b1994897Sopenharmony_ci# See the License for the specific language governing permissions and 12b1994897Sopenharmony_ci# limitations under the License. 13b1994897Sopenharmony_ci 14b1994897Sopenharmony_cirequire 'delegate' 15b1994897Sopenharmony_cirequire 'ostruct' 16b1994897Sopenharmony_cirequire 'digest' 17b1994897Sopenharmony_cirequire 'set' 18b1994897Sopenharmony_ci 19b1994897Sopenharmony_cimodule Enumerable 20b1994897Sopenharmony_ci def stable_sort_by 21b1994897Sopenharmony_ci sort_by.with_index { |x, idx| [yield(x), idx] } 22b1994897Sopenharmony_ci end 23b1994897Sopenharmony_ciend 24b1994897Sopenharmony_ci 25b1994897Sopenharmony_cimodule Util 26b1994897Sopenharmony_ci module_function 27b1994897Sopenharmony_ci 28b1994897Sopenharmony_ci def parse_acc_signature(sig) 29b1994897Sopenharmony_ci res = [] 30b1994897Sopenharmony_ci if sig.include?('->') 31b1994897Sopenharmony_ci src_type, dst_type = sig.match(/inout:(\w+)->(\w+)/).captures 32b1994897Sopenharmony_ci res << Operand.new('acc', 'out', dst_type) 33b1994897Sopenharmony_ci res << Operand.new('acc', 'in', src_type) 34b1994897Sopenharmony_ci elsif sig.include?(':') 35b1994897Sopenharmony_ci srcdst, type = sig.match(/(\w+):(\w+)/).captures 36b1994897Sopenharmony_ci if srcdst == 'inout' 37b1994897Sopenharmony_ci res << Operand.new('acc', 'out', type) 38b1994897Sopenharmony_ci res << Operand.new('acc', 'in', type) 39b1994897Sopenharmony_ci else 40b1994897Sopenharmony_ci res << Operand.new('acc', srcdst, type) 41b1994897Sopenharmony_ci end 42b1994897Sopenharmony_ci elsif sig != 'none' 43b1994897Sopenharmony_ci raise "Unexpected accumulator signature: #{sig}" 44b1994897Sopenharmony_ci end 45b1994897Sopenharmony_ci res 46b1994897Sopenharmony_ci end 47b1994897Sopenharmony_ci 48b1994897Sopenharmony_ci def parse_operand_signature(sig) 49b1994897Sopenharmony_ci operand_parts = sig.split(':') 50b1994897Sopenharmony_ci case operand_parts.size 51b1994897Sopenharmony_ci when 1 52b1994897Sopenharmony_ci name = operand_parts[0] 53b1994897Sopenharmony_ci srcdst = :in 54b1994897Sopenharmony_ci type = 'none' 55b1994897Sopenharmony_ci when 2 56b1994897Sopenharmony_ci name, type = operand_parts 57b1994897Sopenharmony_ci srcdst = :in 58b1994897Sopenharmony_ci when 3 59b1994897Sopenharmony_ci name, srcdst, type = operand_parts 60b1994897Sopenharmony_ci else 61b1994897Sopenharmony_ci raise "Unexpected operand signature: #{sig}" 62b1994897Sopenharmony_ci end 63b1994897Sopenharmony_ci [name, srcdst, type] 64b1994897Sopenharmony_ci end 65b1994897Sopenharmony_ciend 66b1994897Sopenharmony_ci 67b1994897Sopenharmony_cimodule FreezeMixin 68b1994897Sopenharmony_ci class << self 69b1994897Sopenharmony_ci def included(base) 70b1994897Sopenharmony_ci base.extend ClassMethods 71b1994897Sopenharmony_ci end 72b1994897Sopenharmony_ci end 73b1994897Sopenharmony_ci 74b1994897Sopenharmony_ci module ClassMethods 75b1994897Sopenharmony_ci def freeze_defined_methods 76b1994897Sopenharmony_ci @frozen = instance_methods.map { |m| [m, true] }.to_h 77b1994897Sopenharmony_ci end 78b1994897Sopenharmony_ci 79b1994897Sopenharmony_ci def frozen?(name) 80b1994897Sopenharmony_ci defined?(@frozen) && @frozen[name] 81b1994897Sopenharmony_ci end 82b1994897Sopenharmony_ci 83b1994897Sopenharmony_ci def method_added(name) 84b1994897Sopenharmony_ci raise "Method '#{name}' has been already defined" if frozen?(name) 85b1994897Sopenharmony_ci 86b1994897Sopenharmony_ci super 87b1994897Sopenharmony_ci end 88b1994897Sopenharmony_ci end 89b1994897Sopenharmony_ciend 90b1994897Sopenharmony_ci 91b1994897Sopenharmony_ci# Methods for YAML instructions 92b1994897Sopenharmony_ci# 'Instruction' instances are created for every format of every isa.yaml 93b1994897Sopenharmony_ci# instruction and inherit properties of its instruction group. 94b1994897Sopenharmony_ci# 95b1994897Sopenharmony_ciclass Instruction < SimpleDelegator 96b1994897Sopenharmony_ci # Signature without operands 97b1994897Sopenharmony_ci def mnemonic 98b1994897Sopenharmony_ci sig.split(' ')[0] 99b1994897Sopenharmony_ci end 100b1994897Sopenharmony_ci 101b1994897Sopenharmony_ci # Mnemonic stripped from type info 102b1994897Sopenharmony_ci def stripped_mnemonic 103b1994897Sopenharmony_ci mnemonic.split('.')[0] 104b1994897Sopenharmony_ci end 105b1994897Sopenharmony_ci 106b1994897Sopenharmony_ci # Unique (and not very long) identifier for all instructions 107b1994897Sopenharmony_ci def opcode 108b1994897Sopenharmony_ci mn = mnemonic.tr('.', '_') 109b1994897Sopenharmony_ci fmt = format.pretty 110b1994897Sopenharmony_ci if fmt == 'none' 111b1994897Sopenharmony_ci mn 112b1994897Sopenharmony_ci else 113b1994897Sopenharmony_ci "#{mn}_#{fmt}" 114b1994897Sopenharmony_ci end 115b1994897Sopenharmony_ci end 116b1994897Sopenharmony_ci 117b1994897Sopenharmony_ci def prefix 118b1994897Sopenharmony_ci name = dig(:prefix) 119b1994897Sopenharmony_ci Panda.prefixes_hash[name] if name 120b1994897Sopenharmony_ci end 121b1994897Sopenharmony_ci 122b1994897Sopenharmony_ci # Suggested handler name 123b1994897Sopenharmony_ci def handler_name 124b1994897Sopenharmony_ci opcode.upcase 125b1994897Sopenharmony_ci end 126b1994897Sopenharmony_ci 127b1994897Sopenharmony_ci def intrinsic_name 128b1994897Sopenharmony_ci dig(:intrinsic_name) 129b1994897Sopenharmony_ci end 130b1994897Sopenharmony_ci 131b1994897Sopenharmony_ci def compilable? 132b1994897Sopenharmony_ci properties.empty? || (!properties.include? 'not_compilable') 133b1994897Sopenharmony_ci end 134b1994897Sopenharmony_ci 135b1994897Sopenharmony_ci def inlinable? 136b1994897Sopenharmony_ci properties.include? 'inlinable' 137b1994897Sopenharmony_ci end 138b1994897Sopenharmony_ci 139b1994897Sopenharmony_ci def opcode_idx 140b1994897Sopenharmony_ci if prefix 141b1994897Sopenharmony_ci dig(:opcode_idx) << 8 | prefix.opcode_idx 142b1994897Sopenharmony_ci else 143b1994897Sopenharmony_ci dig(:opcode_idx) 144b1994897Sopenharmony_ci end 145b1994897Sopenharmony_ci end 146b1994897Sopenharmony_ci 147b1994897Sopenharmony_ci # Format instance for raw-data format name 148b1994897Sopenharmony_ci def format 149b1994897Sopenharmony_ci Panda.format_hash[dig(:format)] 150b1994897Sopenharmony_ci end 151b1994897Sopenharmony_ci 152b1994897Sopenharmony_ci # Array of explicit operands 153b1994897Sopenharmony_ci cached def operands 154b1994897Sopenharmony_ci return [] unless sig.include? ' ' 155b1994897Sopenharmony_ci 156b1994897Sopenharmony_ci _, operands = sig.match(/(\S+) (.+)/).captures 157b1994897Sopenharmony_ci operands = operands.split(', ') 158b1994897Sopenharmony_ci ops_encoding = format.encoding 159b1994897Sopenharmony_ci 160b1994897Sopenharmony_ci count = 0 161b1994897Sopenharmony_ci operands.map do |operand| 162b1994897Sopenharmony_ci name, srcdst, type = Util.parse_operand_signature(operand) 163b1994897Sopenharmony_ci if name.end_with?('id') 164b1994897Sopenharmony_ci count += 1 165b1994897Sopenharmony_ci end 166b1994897Sopenharmony_ci end 167b1994897Sopenharmony_ci 168b1994897Sopenharmony_ci id_count = 1 169b1994897Sopenharmony_ci operands.map do |operand| 170b1994897Sopenharmony_ci name, srcdst, type = Util.parse_operand_signature(operand) 171b1994897Sopenharmony_ci key = name 172b1994897Sopenharmony_ci if name.end_with?('id') 173b1994897Sopenharmony_ci key = 'id' 174b1994897Sopenharmony_ci if count > 1 175b1994897Sopenharmony_ci key += id_count.to_s 176b1994897Sopenharmony_ci id_count = id_count + 1 177b1994897Sopenharmony_ci end 178b1994897Sopenharmony_ci end 179b1994897Sopenharmony_ci Operand.new(name, srcdst, type, ops_encoding[key].width, ops_encoding[key].offset) 180b1994897Sopenharmony_ci end 181b1994897Sopenharmony_ci end 182b1994897Sopenharmony_ci 183b1994897Sopenharmony_ci # Used by compiler 184b1994897Sopenharmony_ci # Operands array preceeded with accumulator as if it was a regular operand 185b1994897Sopenharmony_ci # Registers that are both destination and source are uncoupled 186b1994897Sopenharmony_ci cached def acc_and_operands 187b1994897Sopenharmony_ci res = Util.parse_acc_signature(acc) 188b1994897Sopenharmony_ci operands.each_with_object(res) do |op, ops| 189b1994897Sopenharmony_ci if op.dst? && op.src? 190b1994897Sopenharmony_ci ops << Operand.new(op.name, 'out', op.type, op.width, op.offset) 191b1994897Sopenharmony_ci ops << Operand.new(op.name, 'in', op.type, op.width, op.offset) 192b1994897Sopenharmony_ci else 193b1994897Sopenharmony_ci ops << op 194b1994897Sopenharmony_ci end 195b1994897Sopenharmony_ci end 196b1994897Sopenharmony_ci end 197b1994897Sopenharmony_ci 198b1994897Sopenharmony_ci cached def properties 199b1994897Sopenharmony_ci props = dig(:properties) || [] 200b1994897Sopenharmony_ci # Added for back compatibility: 201b1994897Sopenharmony_ci add_props = [] 202b1994897Sopenharmony_ci add_props << 'acc_write' if acc_write? 203b1994897Sopenharmony_ci add_props << 'acc_read' if acc_read? 204b1994897Sopenharmony_ci add_props << 'acc_none' if acc_none? 205b1994897Sopenharmony_ci props + add_props 206b1994897Sopenharmony_ci end 207b1994897Sopenharmony_ci 208b1994897Sopenharmony_ci cached def real_properties 209b1994897Sopenharmony_ci filter = [] 210b1994897Sopenharmony_ci properties.each do |p| 211b1994897Sopenharmony_ci if p != 'acc_write' && p != 'acc_read' && p != 'acc_none' 212b1994897Sopenharmony_ci filter << p 213b1994897Sopenharmony_ci end 214b1994897Sopenharmony_ci end 215b1994897Sopenharmony_ci filter << 'acc_write' if acc_write? 216b1994897Sopenharmony_ci filter << 'acc_read' if acc_read? 217b1994897Sopenharmony_ci filter << 'acc_none' if acc_none? 218b1994897Sopenharmony_ci return filter 219b1994897Sopenharmony_ci end 220b1994897Sopenharmony_ci 221b1994897Sopenharmony_ci 222b1994897Sopenharmony_ci def type(index) 223b1994897Sopenharmony_ci acc_and_operands.select(&:src?)[index].type || 'none' 224b1994897Sopenharmony_ci end 225b1994897Sopenharmony_ci 226b1994897Sopenharmony_ci # Type of single destination operand ("none" if there are no such) 227b1994897Sopenharmony_ci def dtype 228b1994897Sopenharmony_ci acc_and_operands.select(&:dst?).first&.type || 'none' 229b1994897Sopenharmony_ci end 230b1994897Sopenharmony_ci 231b1994897Sopenharmony_ci # Shortcut for querying 'float' property 232b1994897Sopenharmony_ci def float? 233b1994897Sopenharmony_ci properties.include? 'float' 234b1994897Sopenharmony_ci end 235b1994897Sopenharmony_ci 236b1994897Sopenharmony_ci # Shortcut for querying 'jump' property 237b1994897Sopenharmony_ci def jump? 238b1994897Sopenharmony_ci properties.include? 'jump' 239b1994897Sopenharmony_ci end 240b1994897Sopenharmony_ci 241b1994897Sopenharmony_ci # Shortcut for querying 'conditional' property 242b1994897Sopenharmony_ci def conditional? 243b1994897Sopenharmony_ci properties.include? 'conditional' 244b1994897Sopenharmony_ci end 245b1994897Sopenharmony_ci 246b1994897Sopenharmony_ci # Shortcut for querying 'x_none' exception 247b1994897Sopenharmony_ci def throwing? 248b1994897Sopenharmony_ci !exceptions.include? 'x_none' 249b1994897Sopenharmony_ci end 250b1994897Sopenharmony_ci 251b1994897Sopenharmony_ci def acc_read? 252b1994897Sopenharmony_ci !acc_and_operands.select(&:acc?).select(&:src?).empty? 253b1994897Sopenharmony_ci end 254b1994897Sopenharmony_ci 255b1994897Sopenharmony_ci def acc_write? 256b1994897Sopenharmony_ci !acc_and_operands.select(&:acc?).select(&:dst?).empty? 257b1994897Sopenharmony_ci end 258b1994897Sopenharmony_ci 259b1994897Sopenharmony_ci def acc_none? 260b1994897Sopenharmony_ci acc_and_operands.select(&:acc?).empty? 261b1994897Sopenharmony_ci end 262b1994897Sopenharmony_ci 263b1994897Sopenharmony_ci def namespace 264b1994897Sopenharmony_ci dig(:namespace) || 'core' 265b1994897Sopenharmony_ci end 266b1994897Sopenharmony_ci 267b1994897Sopenharmony_ci def is_range_0? 268b1994897Sopenharmony_ci properties.include?('range_0') 269b1994897Sopenharmony_ci end 270b1994897Sopenharmony_ci 271b1994897Sopenharmony_ci def is_range_1? 272b1994897Sopenharmony_ci properties.include?('range_1') 273b1994897Sopenharmony_ci end 274b1994897Sopenharmony_ci 275b1994897Sopenharmony_ci def is_range_instruction? 276b1994897Sopenharmony_ci is_range_0? || is_range_1? 277b1994897Sopenharmony_ci end 278b1994897Sopenharmony_ci 279b1994897Sopenharmony_ci def is_return_instruction? 280b1994897Sopenharmony_ci properties.include?('return') 281b1994897Sopenharmony_ci end 282b1994897Sopenharmony_ci 283b1994897Sopenharmony_ci def is_unconditional_throw_instruction? 284b1994897Sopenharmony_ci dig(:prefix) == 'throw' && !properties.include?('conditional_throw') 285b1994897Sopenharmony_ci end 286b1994897Sopenharmony_ci 287b1994897Sopenharmony_ci include FreezeMixin 288b1994897Sopenharmony_ci freeze_defined_methods 289b1994897Sopenharmony_ciend 290b1994897Sopenharmony_ci 291b1994897Sopenharmony_ciclass Prefix < SimpleDelegator 292b1994897Sopenharmony_ci # Suggested handler name 293b1994897Sopenharmony_ci def handler_name 294b1994897Sopenharmony_ci name.upcase 295b1994897Sopenharmony_ci end 296b1994897Sopenharmony_ciend 297b1994897Sopenharmony_ci 298b1994897Sopenharmony_ci# Dummy class for invalid handlers 299b1994897Sopenharmony_ciclass Invalid 300b1994897Sopenharmony_ci def handler_name 301b1994897Sopenharmony_ci 'INVALID' 302b1994897Sopenharmony_ci end 303b1994897Sopenharmony_ciend 304b1994897Sopenharmony_ci 305b1994897Sopenharmony_ci# Methods over format names 306b1994897Sopenharmony_ci# 307b1994897Sopenharmony_ciclass Format 308b1994897Sopenharmony_ci attr_reader :name 309b1994897Sopenharmony_ci 310b1994897Sopenharmony_ci def initialize(name) 311b1994897Sopenharmony_ci @name = name 312b1994897Sopenharmony_ci end 313b1994897Sopenharmony_ci 314b1994897Sopenharmony_ci cached def pretty 315b1994897Sopenharmony_ci name.sub('op_', '').gsub(/id[0-9]?/, 'id').gsub(/imm[0-9]?/, 'imm').gsub(/v[0-9]?/, 'v').gsub(/_([0-9]+)/, '\1') 316b1994897Sopenharmony_ci end 317b1994897Sopenharmony_ci 318b1994897Sopenharmony_ci def prefixed? 319b1994897Sopenharmony_ci name.start_with?('pref_') 320b1994897Sopenharmony_ci end 321b1994897Sopenharmony_ci 322b1994897Sopenharmony_ci cached def size 323b1994897Sopenharmony_ci bits = pretty.gsub(/[a-z]/, '').split('_').map(&:to_i).sum 324b1994897Sopenharmony_ci raise "Incorrect format name #{name}" if bits % 8 != 0 325b1994897Sopenharmony_ci 326b1994897Sopenharmony_ci opcode_bytes = prefixed? ? 2 : 1 327b1994897Sopenharmony_ci bits / 8 + opcode_bytes 328b1994897Sopenharmony_ci end 329b1994897Sopenharmony_ci 330b1994897Sopenharmony_ci cached def encoding 331b1994897Sopenharmony_ci return {} if name.end_with?('_none') 332b1994897Sopenharmony_ci 333b1994897Sopenharmony_ci offset = prefixed? ? 16 : 8 334b1994897Sopenharmony_ci encoding = {} 335b1994897Sopenharmony_ci encoding.default_proc = proc { |_, k| raise KeyError, "#{k} not found" } 336b1994897Sopenharmony_ci name.sub('pref_', '').sub('op_', '').split('_').each_slice(2).map do |name, width| 337b1994897Sopenharmony_ci op = OpenStruct.new 338b1994897Sopenharmony_ci op.name = name 339b1994897Sopenharmony_ci op.width = width.to_i 340b1994897Sopenharmony_ci op.offset = offset 341b1994897Sopenharmony_ci offset += op.width 342b1994897Sopenharmony_ci encoding[name] = op 343b1994897Sopenharmony_ci end 344b1994897Sopenharmony_ci encoding 345b1994897Sopenharmony_ci end 346b1994897Sopenharmony_ci 347b1994897Sopenharmony_ci include FreezeMixin 348b1994897Sopenharmony_ci freeze_defined_methods 349b1994897Sopenharmony_ciend 350b1994897Sopenharmony_ci 351b1994897Sopenharmony_ci# Operand types and encoding 352b1994897Sopenharmony_ci# 353b1994897Sopenharmony_ciclass Operand 354b1994897Sopenharmony_ci attr_reader :name, :type, :offset, :width 355b1994897Sopenharmony_ci 356b1994897Sopenharmony_ci def initialize(name, srcdst, type, width = 0, offset = 0) 357b1994897Sopenharmony_ci @name = name.to_s.gsub(/[0-9]/, '').to_sym 358b1994897Sopenharmony_ci unless %i[v acc imm method_id type_id field_id string_id literalarray_id].include?(@name) 359b1994897Sopenharmony_ci raise "Incorrect operand #{name}" 360b1994897Sopenharmony_ci end 361b1994897Sopenharmony_ci 362b1994897Sopenharmony_ci @srcdst = srcdst.to_sym || :in 363b1994897Sopenharmony_ci types = %i[none u1 u2 i8 u8 i16 u16 i32 u32 b32 f32 i64 u64 b64 f64 ref top any] 364b1994897Sopenharmony_ci raise "Incorrect type #{type}" unless types.include?(type.sub('[]', '').to_sym) 365b1994897Sopenharmony_ci 366b1994897Sopenharmony_ci @type = type 367b1994897Sopenharmony_ci @width = width 368b1994897Sopenharmony_ci @offset = offset 369b1994897Sopenharmony_ci end 370b1994897Sopenharmony_ci 371b1994897Sopenharmony_ci def reg? 372b1994897Sopenharmony_ci @name == :v 373b1994897Sopenharmony_ci end 374b1994897Sopenharmony_ci 375b1994897Sopenharmony_ci def acc? 376b1994897Sopenharmony_ci @name == :acc 377b1994897Sopenharmony_ci end 378b1994897Sopenharmony_ci 379b1994897Sopenharmony_ci def imm? 380b1994897Sopenharmony_ci @name == :imm 381b1994897Sopenharmony_ci end 382b1994897Sopenharmony_ci 383b1994897Sopenharmony_ci def is_float_imm? 384b1994897Sopenharmony_ci %i[f32 f64].include?(@type.to_sym) 385b1994897Sopenharmony_ci end 386b1994897Sopenharmony_ci 387b1994897Sopenharmony_ci def is_signed_imm? 388b1994897Sopenharmony_ci %i[i8 i16 i32 i64].include?(@type.to_sym) 389b1994897Sopenharmony_ci end 390b1994897Sopenharmony_ci 391b1994897Sopenharmony_ci def is_unsigned_imm? 392b1994897Sopenharmony_ci %i[u1 u2 u8 u16 u32 u64].include?(@type.to_sym) 393b1994897Sopenharmony_ci end 394b1994897Sopenharmony_ci 395b1994897Sopenharmony_ci def id? 396b1994897Sopenharmony_ci %i[method_id type_id field_id string_id literalarray_id].include?(@name) 397b1994897Sopenharmony_ci end 398b1994897Sopenharmony_ci 399b1994897Sopenharmony_ci def method_id? 400b1994897Sopenharmony_ci %i[method_id].include?(@name) 401b1994897Sopenharmony_ci end 402b1994897Sopenharmony_ci 403b1994897Sopenharmony_ci def string_id? 404b1994897Sopenharmony_ci %i[string_id].include?(@name) 405b1994897Sopenharmony_ci end 406b1994897Sopenharmony_ci 407b1994897Sopenharmony_ci def literalarray_id? 408b1994897Sopenharmony_ci %i[literalarray_id].include?(@name) 409b1994897Sopenharmony_ci end 410b1994897Sopenharmony_ci 411b1994897Sopenharmony_ci def dst? 412b1994897Sopenharmony_ci %i[inout out].include?(@srcdst) 413b1994897Sopenharmony_ci end 414b1994897Sopenharmony_ci 415b1994897Sopenharmony_ci def src? 416b1994897Sopenharmony_ci %i[inout in].include?(@srcdst) 417b1994897Sopenharmony_ci end 418b1994897Sopenharmony_ci 419b1994897Sopenharmony_ci def size 420b1994897Sopenharmony_ci @type[1..-1].to_i 421b1994897Sopenharmony_ci end 422b1994897Sopenharmony_ci 423b1994897Sopenharmony_ci include FreezeMixin 424b1994897Sopenharmony_ci freeze_defined_methods 425b1994897Sopenharmony_ciend 426b1994897Sopenharmony_ci 427b1994897Sopenharmony_ci# Helper class for generating dispatch tables 428b1994897Sopenharmony_ciclass DispatchTable 429b1994897Sopenharmony_ci # Canonical order of dispatch table consisting of 430b1994897Sopenharmony_ci # * non-prefixed instructions handlers 431b1994897Sopenharmony_ci # * invalid handlers 432b1994897Sopenharmony_ci # * prefix handlers that re-dispatch to prefixed instruction based on second byte of opcode_idx 433b1994897Sopenharmony_ci # * prefixed instructions handlers, in the order of prefixes 434b1994897Sopenharmony_ci # Return array with proposed handler names 435b1994897Sopenharmony_ci def handler_names 436b1994897Sopenharmony_ci handlers = Panda.instructions.reject(&:prefix) + 437b1994897Sopenharmony_ci Array.new(invalid_non_prefixed_interval.size, Invalid.new) + 438b1994897Sopenharmony_ci Panda.prefixes.select(&:public?) + 439b1994897Sopenharmony_ci Array.new(invalid_prefixes_interval.size, Invalid.new) + 440b1994897Sopenharmony_ci Panda.prefixes.reject(&:public?) + 441b1994897Sopenharmony_ci Panda.instructions.select(&:prefix).stable_sort_by { |i| Panda.prefixes_hash[i.prefix.name].opcode_idx } 442b1994897Sopenharmony_ci 443b1994897Sopenharmony_ci handlers.map(&:handler_name) 444b1994897Sopenharmony_ci end 445b1994897Sopenharmony_ci 446b1994897Sopenharmony_ci def invalid_non_prefixed_interval 447b1994897Sopenharmony_ci (Panda.instructions.reject(&:prefix).map(&:opcode_idx).max + 1)..(Panda.prefixes.map(&:opcode_idx).min - 1) 448b1994897Sopenharmony_ci end 449b1994897Sopenharmony_ci 450b1994897Sopenharmony_ci def invalid_prefixes_interval 451b1994897Sopenharmony_ci max_invalid_idx = Panda.prefixes.reject(&:public?).map(&:opcode_idx).min || 256 452b1994897Sopenharmony_ci (Panda.prefixes.select(&:public?).map(&:opcode_idx).max + 1)..(max_invalid_idx - 1) 453b1994897Sopenharmony_ci end 454b1994897Sopenharmony_ci 455b1994897Sopenharmony_ci # Maximum value for secondary dispatch index for given prefix name 456b1994897Sopenharmony_ci def secondary_opcode_bound(prefix) 457b1994897Sopenharmony_ci prefix_data[prefix.name][:number_of_insns] - 1 458b1994897Sopenharmony_ci end 459b1994897Sopenharmony_ci 460b1994897Sopenharmony_ci # Offset in dispatch table for handlers of instructions for given prefix name 461b1994897Sopenharmony_ci def secondary_opcode_offset(prefix) 462b1994897Sopenharmony_ci 256 + prefix_data[prefix.name][:delta] 463b1994897Sopenharmony_ci end 464b1994897Sopenharmony_ci 465b1994897Sopenharmony_ci private 466b1994897Sopenharmony_ci 467b1994897Sopenharmony_ci cached def prefix_data 468b1994897Sopenharmony_ci cur_delta = 0 469b1994897Sopenharmony_ci Panda.prefixes.each_with_object({}) do |p, obj| 470b1994897Sopenharmony_ci prefix_instructions_num = Panda.instructions.select { |i| i.prefix && (i.prefix.name == p.name) }.size 471b1994897Sopenharmony_ci obj[p.name] = { delta: cur_delta, number_of_insns: prefix_instructions_num } 472b1994897Sopenharmony_ci cur_delta += prefix_instructions_num 473b1994897Sopenharmony_ci end 474b1994897Sopenharmony_ci end 475b1994897Sopenharmony_ciend 476b1994897Sopenharmony_ci 477b1994897Sopenharmony_ci# Auxilary classes for opcode assignment 478b1994897Sopenharmony_ciclass OpcodeAssigner 479b1994897Sopenharmony_ci def initialize 480b1994897Sopenharmony_ci @table = Hash.new { |h, k| h[k] = Set.new } 481b1994897Sopenharmony_ci @all_opcodes = Set.new(0..255) 482b1994897Sopenharmony_ci end 483b1994897Sopenharmony_ci 484b1994897Sopenharmony_ci def consume(item) 485b1994897Sopenharmony_ci raise 'Cannot consume instruction without opcode' unless item.opcode_idx 486b1994897Sopenharmony_ci 487b1994897Sopenharmony_ci @table[prefix(item)] << item.opcode_idx 488b1994897Sopenharmony_ci end 489b1994897Sopenharmony_ci 490b1994897Sopenharmony_ci def yield_opcode(item) 491b1994897Sopenharmony_ci return item.opcode_idx if item.opcode_idx 492b1994897Sopenharmony_ci 493b1994897Sopenharmony_ci opcodes = @table[prefix(item)] 494b1994897Sopenharmony_ci choose_opcode(opcodes) 495b1994897Sopenharmony_ci end 496b1994897Sopenharmony_ci 497b1994897Sopenharmony_ci private 498b1994897Sopenharmony_ci 499b1994897Sopenharmony_ci def choose_opcode(occupied_opcodes) 500b1994897Sopenharmony_ci (@all_opcodes - occupied_opcodes).min 501b1994897Sopenharmony_ci end 502b1994897Sopenharmony_ci 503b1994897Sopenharmony_ci def prefix(item) 504b1994897Sopenharmony_ci item.prefix.nil? ? 'non_prefixed' : item.prefix 505b1994897Sopenharmony_ci end 506b1994897Sopenharmony_ciend 507b1994897Sopenharmony_ci 508b1994897Sopenharmony_ciclass PrefixOpcodeAssigner < OpcodeAssigner 509b1994897Sopenharmony_ci private 510b1994897Sopenharmony_ci 511b1994897Sopenharmony_ci # override opcodes assignment for prefixes 512b1994897Sopenharmony_ci def choose_opcode(occupied_opcodes) 513b1994897Sopenharmony_ci (@all_opcodes - occupied_opcodes).max 514b1994897Sopenharmony_ci end 515b1994897Sopenharmony_ciend 516b1994897Sopenharmony_ci 517b1994897Sopenharmony_ci# A bunch of handy methods for template generating 518b1994897Sopenharmony_ci# 519b1994897Sopenharmony_ci# All yaml properties are accessible by '.' syntax, 520b1994897Sopenharmony_ci# e.g. 'Panda::groups[0].instruction[0].format' 521b1994897Sopenharmony_ci# 522b1994897Sopenharmony_cimodule Panda 523b1994897Sopenharmony_ci module_function 524b1994897Sopenharmony_ci 525b1994897Sopenharmony_ci def properties 526b1994897Sopenharmony_ci @data.properties + 527b1994897Sopenharmony_ci [OpenStruct.new(tag: 'acc_none', description: 'Doesn\'t use accumulator register.'), 528b1994897Sopenharmony_ci OpenStruct.new(tag: 'acc_read', description: 'Use accumulator as a first source operand.'), 529b1994897Sopenharmony_ci OpenStruct.new(tag: 'acc_write', description: 'Use accumulator as a destination operand.')] 530b1994897Sopenharmony_ci end 531b1994897Sopenharmony_ci 532b1994897Sopenharmony_ci # Hash with exception tag as a key and exception description as a value 533b1994897Sopenharmony_ci cached def exceptions_hash 534b1994897Sopenharmony_ci convert_to_hash(exceptions) 535b1994897Sopenharmony_ci end 536b1994897Sopenharmony_ci 537b1994897Sopenharmony_ci # Hash with property tag as a key and property description as a value 538b1994897Sopenharmony_ci cached def properties_hash 539b1994897Sopenharmony_ci convert_to_hash(properties) 540b1994897Sopenharmony_ci end 541b1994897Sopenharmony_ci 542b1994897Sopenharmony_ci # Hash with verification tag as a key and verification description as a value 543b1994897Sopenharmony_ci cached def verification_hash 544b1994897Sopenharmony_ci convert_to_hash(verification) 545b1994897Sopenharmony_ci end 546b1994897Sopenharmony_ci 547b1994897Sopenharmony_ci cached def prefixes_hash 548b1994897Sopenharmony_ci hash = prefixes.map { |p| [p.name, p] }.to_h 549b1994897Sopenharmony_ci hash.default_proc = proc { |_, k| raise KeyError, "#{k} not found" } 550b1994897Sopenharmony_ci hash 551b1994897Sopenharmony_ci end 552b1994897Sopenharmony_ci 553b1994897Sopenharmony_ci # Hash from format names to Format instances 554b1994897Sopenharmony_ci cached def format_hash 555b1994897Sopenharmony_ci each_data_instruction.with_object([]) do |instruction, fmts| 556b1994897Sopenharmony_ci fmt_name = instruction.format 557b1994897Sopenharmony_ci fmts << [fmt_name, Format.new(fmt_name)] 558b1994897Sopenharmony_ci end.to_h 559b1994897Sopenharmony_ci end 560b1994897Sopenharmony_ci 561b1994897Sopenharmony_ci # Array of Instruction instances for every possible instruction 562b1994897Sopenharmony_ci cached def instructions 563b1994897Sopenharmony_ci opcodes = OpcodeAssigner.new 564b1994897Sopenharmony_ci tmp_public = initialize_instructions(opcodes) { |ins| !ins.opcode_idx.nil? } 565b1994897Sopenharmony_ci tmp_private = initialize_instructions(opcodes) { |ins| ins.opcode_idx.nil? } 566b1994897Sopenharmony_ci tmp = tmp_public + tmp_private 567b1994897Sopenharmony_ci @instructions = tmp.sort_by(&:opcode_idx) 568b1994897Sopenharmony_ci end 569b1994897Sopenharmony_ci 570b1994897Sopenharmony_ci cached def prefixes 571b1994897Sopenharmony_ci opcodes = PrefixOpcodeAssigner.new 572b1994897Sopenharmony_ci tmp_public = initialize_prefixes(opcodes) { |p| !p.opcode_idx.nil? } 573b1994897Sopenharmony_ci tmp_private = initialize_prefixes(opcodes) { |p| p.opcode_idx.nil? } 574b1994897Sopenharmony_ci tmp = tmp_public + tmp_private 575b1994897Sopenharmony_ci @prefixes = tmp.sort_by(&:opcode_idx) 576b1994897Sopenharmony_ci end 577b1994897Sopenharmony_ci 578b1994897Sopenharmony_ci def dispatch_table 579b1994897Sopenharmony_ci DispatchTable.new 580b1994897Sopenharmony_ci end 581b1994897Sopenharmony_ci 582b1994897Sopenharmony_ci # Array of all Format instances 583b1994897Sopenharmony_ci def formats 584b1994897Sopenharmony_ci format_hash.values.uniq(&:pretty).sort_by(&:pretty) 585b1994897Sopenharmony_ci end 586b1994897Sopenharmony_ci 587b1994897Sopenharmony_ci # delegating part of module 588b1994897Sopenharmony_ci # 589b1994897Sopenharmony_ci def wrap_data(data) 590b1994897Sopenharmony_ci @data = data 591b1994897Sopenharmony_ci end 592b1994897Sopenharmony_ci 593b1994897Sopenharmony_ci def respond_to_missing?(method_name, include_private = false) 594b1994897Sopenharmony_ci @data.respond_to?(method_name, include_private) 595b1994897Sopenharmony_ci end 596b1994897Sopenharmony_ci 597b1994897Sopenharmony_ci def method_missing(method, *args, &block) 598b1994897Sopenharmony_ci if respond_to_missing? method 599b1994897Sopenharmony_ci @data.send(method, *args, &block) 600b1994897Sopenharmony_ci else 601b1994897Sopenharmony_ci super 602b1994897Sopenharmony_ci end 603b1994897Sopenharmony_ci end 604b1994897Sopenharmony_ci 605b1994897Sopenharmony_ci # private functions 606b1994897Sopenharmony_ci # 607b1994897Sopenharmony_ci private_class_method def convert_to_hash(arr) 608b1994897Sopenharmony_ci hash = arr.map { |i| [i.tag, i.description] }.to_h 609b1994897Sopenharmony_ci hash.default_proc = proc { |_, k| raise KeyError, "#{k} not found" } 610b1994897Sopenharmony_ci hash 611b1994897Sopenharmony_ci end 612b1994897Sopenharmony_ci 613b1994897Sopenharmony_ci private_class_method def merge_group_and_insn(group, insn) 614b1994897Sopenharmony_ci props = group.to_h 615b1994897Sopenharmony_ci props.delete(:instructions) 616b1994897Sopenharmony_ci props.merge(insn.to_h) do |_, old, new| 617b1994897Sopenharmony_ci if old.is_a?(Array) && new.is_a?(Array) 618b1994897Sopenharmony_ci old | new # extend array-like properties instead of overriding 619b1994897Sopenharmony_ci else 620b1994897Sopenharmony_ci new 621b1994897Sopenharmony_ci end 622b1994897Sopenharmony_ci end 623b1994897Sopenharmony_ci end 624b1994897Sopenharmony_ci 625b1994897Sopenharmony_ci private_class_method cached def each_data_instruction 626b1994897Sopenharmony_ci # create separate instance for every instruction format and inherit group properties 627b1994897Sopenharmony_ci groups.each_with_object([]) do |g, obj| 628b1994897Sopenharmony_ci g.instructions.each do |i| 629b1994897Sopenharmony_ci data_insn = merge_group_and_insn(g, i) 630b1994897Sopenharmony_ci if data_insn[:opcode_idx] && (data_insn[:opcode_idx].size != data_insn[:format].size) 631b1994897Sopenharmony_ci raise 'format and opcode_idx arrays should have equal size' 632b1994897Sopenharmony_ci end 633b1994897Sopenharmony_ci 634b1994897Sopenharmony_ci data_insn[:format].each_with_index do |f, idx| 635b1994897Sopenharmony_ci insn = data_insn.dup 636b1994897Sopenharmony_ci insn[:format] = f 637b1994897Sopenharmony_ci insn[:opcode_idx] = data_insn[:opcode_idx][idx] if data_insn[:opcode_idx] 638b1994897Sopenharmony_ci obj << OpenStruct.new(insn) 639b1994897Sopenharmony_ci end 640b1994897Sopenharmony_ci end 641b1994897Sopenharmony_ci end.to_enum 642b1994897Sopenharmony_ci end 643b1994897Sopenharmony_ci 644b1994897Sopenharmony_ci private_class_method def initialize_instructions(opcodes, &block) 645b1994897Sopenharmony_ci each_data_instruction.select(&block).each_with_object([]) do |instruction, insns| 646b1994897Sopenharmony_ci insn = instruction.clone 647b1994897Sopenharmony_ci insn[:public?] = !insn.opcode_idx.nil? 648b1994897Sopenharmony_ci insn.opcode_idx = opcodes.yield_opcode(insn) 649b1994897Sopenharmony_ci opcodes.consume(insn) 650b1994897Sopenharmony_ci insns << Instruction.new(insn) 651b1994897Sopenharmony_ci end 652b1994897Sopenharmony_ci end 653b1994897Sopenharmony_ci 654b1994897Sopenharmony_ci private_class_method def initialize_prefixes(opcodes, &block) 655b1994897Sopenharmony_ci dig(:prefixes).select(&block).each_with_object([]) do |pref, res| 656b1994897Sopenharmony_ci p = pref.clone 657b1994897Sopenharmony_ci p[:public?] = !p.opcode_idx.nil? 658b1994897Sopenharmony_ci p.opcode_idx = opcodes.yield_opcode(p) 659b1994897Sopenharmony_ci opcodes.consume(p) 660b1994897Sopenharmony_ci res << Prefix.new(p) 661b1994897Sopenharmony_ci end 662b1994897Sopenharmony_ci end 663b1994897Sopenharmony_ciend 664b1994897Sopenharmony_ci 665b1994897Sopenharmony_cidef Gen.on_require(data) 666b1994897Sopenharmony_ci Panda.wrap_data(data) 667b1994897Sopenharmony_ciend 668