Class: Idl::AryRangeAssignmentAst

Inherits:
AstNode
  • Object
show all
Includes:
Executable
Defined in:
lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/find_src_registers.rb

Overview

represents an array range assignment

for example:

vec[8:0] = 8'd0

Constant Summary

Constants inherited from AstNode

Idl::AstNode::Bits1Type, Idl::AstNode::Bits32Type, Idl::AstNode::Bits64Type, Idl::AstNode::BoolType, Idl::AstNode::ConstBoolType, Idl::AstNode::PossiblyUnknownBits1Type, Idl::AstNode::PossiblyUnknownBits32Type, Idl::AstNode::PossiblyUnknownBits64Type, Idl::AstNode::ReachableFunctionCacheType, Idl::AstNode::StringType, Idl::AstNode::VoidType

Instance Attribute Summary

Attributes inherited from AstNode

#children, #input, #interval, #parent

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Executable

#executable?

Methods inherited from AstNode

#always_terminates?, #declaration?, #executable?, extract_base_var_name, #find_ancestor, #find_referenced_csrs, #find_src_registers, #freeze_tree, #gen_option_adoc, #input_file, input_from_source_yaml, #inspect, #internal_error, interval_from_source_yaml, #lineno, #lines_around, #pass_find_return_values, #path, #print_ast, #reachable_exceptions, #reachable_functions, #set_input_file, #set_input_file_unless_already_set, #source_line_file_offsets, #source_starting_offset, #source_yaml, #starting_line, #text_value, #truncation_warn, #type_error, #unindent, value_else, #value_else, value_error, #value_error, value_try, #value_try, write_back_nested

Constructor Details

#initialize(input, interval, variable, msb, lsb, write_value) ⇒ AryRangeAssignmentAst

Returns a new instance of AryRangeAssignmentAst.



3105
3106
3107
# File 'lib/idlc/ast.rb', line 3105

def initialize(input, interval, variable, msb, lsb, write_value)
  super(input, interval, [variable, msb, lsb, write_value])
end

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
# File 'lib/idlc/ast.rb', line 3195

def self.from_h(yaml, source_mapper)
  raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "array_range_assignment"

  input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
  interval = interval_from_source_yaml(yaml.fetch("source"))
  AryRangeAssignmentAst.new(
    input, interval,
    T.cast(AstNode.from_h(yaml.fetch("array"), source_mapper), RvalueAst),
    T.cast(AstNode.from_h(yaml.fetch("range").fetch("msb"), source_mapper), RvalueAst),
    T.cast(AstNode.from_h(yaml.fetch("range").fetch("lsb"), source_mapper), RvalueAst),
    T.cast(AstNode.from_h(yaml.fetch("value"), source_mapper), RvalueAst)
  )
end

Instance Method Details

#const_eval?(symtab) ⇒ Boolean

Returns:

  • (Boolean)


3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
# File 'lib/idlc/ast.rb', line 3084

def const_eval?(symtab)
  return false if !variable.const_eval?(symtab)

  if lsb.const_eval?(symtab) && msb.const_eval?(symtab) && write_value.const_eval?(symtab)
    true
  else
    base_name = AstNode.extract_base_var_name(variable)
    type_error "Cannot determine base variable for #{variable.text_value}" if base_name.nil?
    lhs_var = symtab.get(base_name)
    type_error "array #{base_name} has not be declared" if lhs_var.nil?

    lhs_var.const_incompatible!
    false
  end
end

#execute(symtab) ⇒ void

This method returns an undefined value.

“execute” the statement by updating the variables in the symbol table

Parameters:

  • symtab (SymbolTable)

    The symbol table for the context

Raises:

  • ValueError if some part of the statement cannot be executed at compile time



3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
# File 'lib/idlc/ast.rb', line 3148

def execute(symtab)
  return if variable.type(symtab).global?

  value_result = value_try do
    msb_val = msb.value(symtab)
    lsb_val = lsb.value(symtab)

    type_error "MSB (#{msb_val}) is <= LSB (#{lsb_val})" if msb_val <= lsb_val

    rval_val = write_value.value(symtab)
    mask = ((1 << (msb_val - lsb_val + 1)) - 1) << lsb_val

    # Read current value, modify bits
    var_val = variable.value(symtab)
    var_val &= ~mask
    new_val = var_val | ((rval_val << lsb_val) & mask)

    # Write back through the access chain
    AstNode.write_back_nested(variable, new_val, symtab)
    :ok
  end
  value_else(value_result) do
    base_name = T.must(AstNode.extract_base_var_name(variable))
    v = symtab.get(base_name)
    internal_error "did not find array base" if v.nil?
    v.value = nil
    value_error "Either the range or right-hand side of an array range assignment is unknown"
  end
end

#find_dst_registers(symtab) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/idlc/passes/find_src_registers.rb', line 143

def find_dst_registers(symtab)
  return [] unless variable.is_a?(Idl::AryElementAccessAst)

  var_type = variable.var.type(symtab) rescue nil
  return [] unless var_type&.kind == :array &&
                   var_type.sub_type.is_a?(RegFileElementType) &&
                   var_type.qualifiers.include?(:global)

  rf_name = var_type.sub_type.name

  value_result = value_try do
    return [[rf_name, variable.index.value(symtab)]]
  end
  value_else(value_result) do
    if variable.index.type(symtab).const?
      return [[rf_name, variable.index.gen_cpp(symtab, 0)]]
    else
      raise ComplexRegDetermination
    end
  end
end

#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object



20
21
22
# File 'lib/idlc/passes/gen_adoc.rb', line 20

def gen_adoc(indent = 0, indent_spaces: 2)
  "#{' ' * indent}#{variable.gen_adoc(indent, indent_spaces:)}[#{msb.gen_adoc(0, indent_spaces:)}:#{lsb.gen_adoc(0, indent_spaces:)}] = #{write_value.gen_adoc(0, indent_spaces:)}"
end

#lsbObject



3102
# File 'lib/idlc/ast.rb', line 3102

def lsb = @children[2]

#msbObject



3101
# File 'lib/idlc/ast.rb', line 3101

def msb = @children[1]

#nullify_assignments(symtab) ⇒ Object



170
171
172
173
174
175
176
# File 'lib/idlc/passes/prune.rb', line 170

def nullify_assignments(symtab)
  return if variable.type(symtab).global?
  root = variable
  root = root.var while root.is_a?(AryElementAccessAst) || root.is_a?(AryRangeAccessAst)
  var = symtab.get(root.name)
  var.value = nil unless var.nil?
end

#prune(symtab, forced_type: nil) ⇒ Object



914
915
916
917
918
919
920
921
922
923
924
925
926
927
# File 'lib/idlc/passes/prune.rb', line 914

def prune(symtab, forced_type: nil)
  new_ast = AryRangeAssignmentAst.new(
    input, interval,
    variable.dup,
    msb.prune(symtab),
    lsb.prune(symtab),
    write_value.prune(symtab)
  )
  value_try do
    new_ast.execute(symtab)
  end
  # value_else: execute already sets nil on failure, nothing more to do
  new_ast
end

#rhsObject



3143
3144
3145
# File 'lib/idlc/ast.rb', line 3143

def rhs
  write_value
end

#to_hObject



3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
# File 'lib/idlc/ast.rb', line 3183

def to_h = {
  "kind" => "array_range_assignment",
  "array" => variable.to_h,
  "range" => {
    "lsb" => lsb.to_h,
    "msb" => msb.to_h
  },
  "value" => write_value.to_h,
  "source" => source_yaml
}

#to_idlObject



3180
# File 'lib/idlc/ast.rb', line 3180

def to_idl = "#{variable.to_idl}[#{msb.to_idl}:#{lsb.to_idl}] = #{write_value.to_idl}"

#type_check(symtab, strict:) ⇒ void

This method returns an undefined value.

type check this node and all children

Calls to #type and/or #value may depend on type_check being called first with the same symtab. If not, those functions may raise an AstNode::InternalError

Parameters:

Raises:



3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
# File 'lib/idlc/ast.rb', line 3110

def type_check(symtab, strict:)
  variable.type_check(symtab, strict:)
  type_error "#{variable.text_value} must be integral" unless variable.type(symtab).kind == :bits
  type_error "Assigning to a constant" if variable.type(symtab).const?

  msb.type_check(symtab, strict:)
  lsb.type_check(symtab, strict:)

  type_error "MSB must be integral" unless msb.type(symtab).integral?
  type_error "LSB must be integral" unless lsb.type(symtab).integral?

  value_result = value_try do
    msb_value = msb.value(symtab)
    lsb_value = lsb.value(symtab)

    type_error "MSB must be > LSB" unless msb_value > lsb_value
    if variable.type(symtab).width == :unknown
      unless variable.type(symtab).max_width.nil?
        type_error "MSB is out of range" if msb_value >= variable.type(symtab).max_width
      end
    else
      type_error "MSB is out of range" if msb_value >= variable.type(symtab).width
    end
  end
  # OK, don't have to know the value

  write_value.type_check(symtab, strict:)

  unless write_value.type(symtab).integral?
    type_error "Incompatible type in range assignment"
  end
end

#variableObject



3100
# File 'lib/idlc/ast.rb', line 3100

def variable = @children[0]

#write_valueObject



3103
# File 'lib/idlc/ast.rb', line 3103

def write_value = @children[3]