1#!/usr/bin/env ruby
2
3# Copyright (c) 2021-2024 Huawei Device Co., Ltd.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16require_relative 'regmap'
17
18# RegMask class is like bitset
19class RegMask
20  attr_reader :value, :regmap
21
22  def initialize(*args)
23    @value = 0
24    if Options.arch == :arm64
25      @size = 31
26    elsif Options.arch == :arm32
27      @size = 16
28    elsif Options.arch == :x86_64
29      @size = 16
30    end
31    return if args.empty?
32
33    if args[0].is_a?(Regmap)
34      @regmap = args[0]
35      args = args[1..-1]
36    elsif args[0].nil?
37      args = args[1..-1]
38    elsif args[0].is_a?(RegMask)
39      @regmap = args[-0].regmap
40      @value = args[0].value
41      return
42    end
43
44    args.each do |value|
45      if value.is_a?(Symbol)
46        raise "RegMask is initialized with symbol, but Regmap wasn't specified" unless @regmap
47        raise "Regmap doesn't contain value for #{value}" unless @regmap.data.keys.include? value
48        value = @regmap[value]
49      end
50      raise "RegMask is initialized with wrong type: #{value.class}" unless value.is_a?(Integer)
51      self[value] = true
52    end
53  end
54
55  def self.from_value(regmap, value)
56    mask = RegMask.new(regmap)
57    mask.set_value(value)
58    mask
59  end
60
61  def self.from_regmap(regmap, map)
62    mask = RegMask.new(regmap)
63    map.data.each { |_, v| mask[v] = true }
64    mask
65  end
66
67  def set_value(value)
68    raise "RegMask is initialized with wrong type: #{value.class}" unless value.is_a?(Integer)
69    @value = value
70  end
71
72  def []=(position, value)
73    position = @regmap[position] if position.is_a? Symbol
74    raise "Wrong `position` type" unless position.is_a? Integer
75    if value
76      @value |= (1 << position)
77    else
78      @value &= ~(1 << position)
79    end
80  end
81
82  def [](position)
83    position = @regmap[position] if position.is_a? Symbol
84    raise "Wrong `position` type" unless position.is_a? Integer
85    @value & (1 << position) != 0
86  end
87
88  def +(other)
89    if other.is_a? RegMask
90      self.class.from_value(@regmap, @value | other.value)
91    elsif other.is_a? Regmap
92      other_value = other.data.values.inject(0) { |res, x| res | (1 << x) }
93      self.class.from_value(@regmap, @value | other_value)
94    elsif other.is_a? Integer
95      self.class.from_value(@regmap, @value | (1 << other))
96    elsif other.is_a? Symbol
97      raise "Symbol argument is only allowed if Regmap was specified" unless @regmap
98      value = @regmap[other]
99      raise "Register '#{other}' is not found in regmap" unless value
100      self.class.from_value(@regmap, @value | (1 << value))
101    else
102      raise "Unsupported type: #{other.class}"
103    end
104  end
105
106  def -(other)
107    if other.is_a? RegMask
108      self.class.from_value(@regmap, @value & ~other.value)
109    elsif other.is_a? Regmap
110      other_value = other.data.values.inject(0) { |res, x| res | (1 << x) }
111      self.class.from_value(@regmap, @value & ~other_value)
112    elsif other.is_a? Integer
113      self.class.from_value(@regmap, @value & ~(1 << other))
114    elsif other.is_a? Symbol
115      raise "Symbol argument is only allowed if Regmap was specified" unless @regmap
116      value = @regmap[other]
117      raise "Register '#{other}' is not found in regmap" unless value
118      self.class.from_value(@regmap, @value & ~(1 << value))
119    else
120      raise "Unsupported type: #{other.class}"
121    end
122  end
123
124  def ~
125    value = ~@value & ((1 << @size) - 1)
126    self.class.from_value(@regmap, value)
127  end
128
129  def ==(other)
130    @value == other.value
131  end
132
133  def each(&block)
134    if block
135      (0..@size - 1).select { |x| self[x] }.each { |x| yield x }
136    else
137       (0..@size - 1).select { |x| self[x] }
138    end
139  end
140
141  def to_s
142    "[#{each.join(', ')}]"
143  end
144end
145