rggen-default-register-map 0.16.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +3 -3
  4. data/lib/rggen/default_register_map.rb +7 -4
  5. data/lib/rggen/default_register_map/bit_field/bit_assignment.rb +32 -10
  6. data/lib/rggen/default_register_map/bit_field/initial_value.rb +144 -26
  7. data/lib/rggen/default_register_map/bit_field/name.rb +10 -11
  8. data/lib/rggen/default_register_map/bit_field/reference.rb +53 -24
  9. data/lib/rggen/default_register_map/bit_field/type/{rw.rb → rw_w1.rb} +1 -1
  10. data/lib/rggen/default_register_map/bit_field/type/rwe_rwl.rb +17 -0
  11. data/lib/rggen/default_register_map/bit_field/type/{wo.rb → wo_wo1.rb} +1 -1
  12. data/lib/rggen/default_register_map/common/comment.rb +18 -0
  13. data/lib/rggen/default_register_map/register/name.rb +23 -8
  14. data/lib/rggen/default_register_map/register/offset_address.rb +53 -32
  15. data/lib/rggen/default_register_map/register/size.rb +7 -11
  16. data/lib/rggen/default_register_map/register/type.rb +2 -6
  17. data/lib/rggen/default_register_map/register/type/external.rb +11 -0
  18. data/lib/rggen/default_register_map/register/type/indirect.rb +27 -40
  19. data/lib/rggen/default_register_map/register_block/name.rb +4 -9
  20. data/lib/rggen/default_register_map/register_file/name.rb +53 -0
  21. data/lib/rggen/default_register_map/register_file/offset_address.rb +107 -0
  22. data/lib/rggen/default_register_map/register_file/size.rb +60 -0
  23. data/lib/rggen/default_register_map/setup.rb +10 -3
  24. data/lib/rggen/default_register_map/version.rb +1 -1
  25. metadata +11 -8
  26. data/lib/rggen/default_register_map/bit_field/comment.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a07cecea3878d609e000fc36d1e8f41e045686d28548774ba19b44d00089986f
4
- data.tar.gz: 8347d41f0d9ffea4fa01e2d0860f2df4fcc2ab0e8d65ff9f1f7ab6ac84a79590
3
+ metadata.gz: ae013f1baa39fec2b34473f60af4a530444b1bf1124d97f19d266604cf7eb5ff
4
+ data.tar.gz: d3f9ee6009f22d81eab9157f2a3277e3f436aa2167054a2745af71f3e3a8790a
5
5
  SHA512:
6
- metadata.gz: d6375a8b050dbb6ea1a22f384555272cb6b1afc63860d0307625447501b1121941a1fe350f6952f1057eed370e833173ec0497981f85c69ca6973cf518198ac1
7
- data.tar.gz: 54fda95836bd1ab2442885e43e3bb405f81e80918c58f05d0213f09de34a58062de302896492bc157a460a3247d8e658cace7434219d03b5942b9c7a9b1cc5a2
6
+ metadata.gz: 49cb8841485f9d1dba72f4ee7b79af0551a91718079a9df6785b9490c0d9c9efddaacba22057421c818134ad0c6fd5383faf3ae69ccb4a4c5f0c3d4466d36ab7
7
+ data.tar.gz: 1a822488fdefcc6947e8e4a2578ed335b557615effa70e0f57f9b82a29626f0c2658d30e4073461cdd5b1e1d3969d953948f1e3fb66d7dd3b9ca710d5df09c60
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2019 Taichi Ishitani
3
+ Copyright (c) 2019-2020 Taichi Ishitani
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/rggen-default-register-map.svg)](https://badge.fury.io/rb/rggen-default-register-map)
2
- [![Build Status](https://travis-ci.com/rggen/rggen-default-register-map.svg?branch=master)](https://travis-ci.com/rggen/rggen-default-register-map)
2
+ [![CI](https://github.com/rggen/rggen-default-register-map/workflows/CI/badge.svg)](https://github.com/rggen/rggen-default-register-map/actions?query=workflow%3ACI)
3
3
  [![Maintainability](https://api.codeclimate.com/v1/badges/73177494e096af47f09e/maintainability)](https://codeclimate.com/github/rggen/rggen-default-register-map/maintainability)
4
4
  [![codecov](https://codecov.io/gh/rggen/rggen-default-register-map/branch/master/graph/badge.svg)](https://codecov.io/gh/rggen/rggen-default-register-map)
5
5
  [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=rggen_rggen-default-register-map&metric=alert_status)](https://sonarcloud.io/dashboard?id=rggen_rggen-default-register-map)
6
6
  [![Gitter](https://badges.gitter.im/rggen/rggen.svg)](https://gitter.im/rggen/rggen?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
7
7
 
8
8
 
9
- # Rggen::DefaultRegisterMap
9
+ # RgGen::DefaultRegisterMap
10
10
 
11
11
  RgGen::DefaultRegisterMap provides following features.
12
12
 
@@ -38,7 +38,7 @@ Feedbacks, bug reports, questions and etc. are wellcome! You can post them by us
38
38
 
39
39
  ## Copyright & License
40
40
 
41
- Copyright © 2019 Taichi Ishitani. RgGen::DefaultRegisterMap is licensed under the [MIT License](https://opensource.org/licenses/MIT), see [LICENSE](LICENSE) for futher details.
41
+ Copyright © 2019-2020 Taichi Ishitani. RgGen::DefaultRegisterMap is licensed under the [MIT License](https://opensource.org/licenses/MIT), see [LICENSE](LICENSE) for futher details.
42
42
 
43
43
  ## Code of Conduct
44
44
 
@@ -6,7 +6,6 @@ module RgGen
6
6
  module DefaultRegisterMap
7
7
  FEATURES = [
8
8
  'default_register_map/bit_field/bit_assignment',
9
- 'default_register_map/bit_field/comment',
10
9
  'default_register_map/bit_field/initial_value',
11
10
  'default_register_map/bit_field/name',
12
11
  'default_register_map/bit_field/reference',
@@ -16,14 +15,15 @@ module RgGen
16
15
  'default_register_map/bit_field/type/ro',
17
16
  'default_register_map/bit_field/type/rof',
18
17
  'default_register_map/bit_field/type/rs',
19
- 'default_register_map/bit_field/type/rw',
18
+ 'default_register_map/bit_field/type/rw_w1',
20
19
  'default_register_map/bit_field/type/rwc_rws',
21
20
  'default_register_map/bit_field/type/rwe_rwl',
22
21
  'default_register_map/bit_field/type/w0c_w1c',
23
22
  'default_register_map/bit_field/type/w0crs_w1crs_w0src_w1src',
24
23
  'default_register_map/bit_field/type/w0s_w1s',
25
24
  'default_register_map/bit_field/type/w0trg_w1trg',
26
- 'default_register_map/bit_field/type/wo',
25
+ 'default_register_map/bit_field/type/wo_wo1',
26
+ 'default_register_map/common/comment',
27
27
  'default_register_map/global/address_width',
28
28
  'default_register_map/global/bus_width',
29
29
  'default_register_map/register/name',
@@ -33,7 +33,10 @@ module RgGen
33
33
  'default_register_map/register/type/external',
34
34
  'default_register_map/register/type/indirect',
35
35
  'default_register_map/register_block/byte_size',
36
- 'default_register_map/register_block/name'
36
+ 'default_register_map/register_block/name',
37
+ 'default_register_map/register_file/name',
38
+ 'default_register_map/register_file/offset_address',
39
+ 'default_register_map/register_file/size'
37
40
  ].freeze
38
41
 
39
42
  def self.load_features
@@ -19,13 +19,13 @@ RgGen.define_simple_feature(:bit_field, :bit_assignment) do
19
19
  end
20
20
 
21
21
  verify(:feature) do
22
- error_condition { [@lsb, @width, @sequence_size, @step].none? }
22
+ error_condition { [@lsb_base, @width, @sequence_size, @step].none? }
23
23
  message { 'no bit assignment is given' }
24
24
  end
25
25
 
26
26
  verify(:feature) do
27
- error_condition { !@lsb }
28
- message { 'no lsb is given' }
27
+ error_condition { [@lsb_base, @width].none? }
28
+ message { 'neither lsb nor width is given' }
29
29
  end
30
30
 
31
31
  verify(:feature) do
@@ -61,7 +61,11 @@ RgGen.define_simple_feature(:bit_field, :bit_assignment) do
61
61
 
62
62
  private
63
63
 
64
- KEYS = [:lsb, :width, :sequence_size, :step].freeze
64
+ VARIABLE_NAMES = {
65
+ lsb: :@lsb_base, width: :@width, sequence_size: :@sequence_size, step: :@step
66
+ }.freeze
67
+
68
+ KEYS = VARIABLE_NAMES.keys.freeze
65
69
 
66
70
  def preprocess(value)
67
71
  if value.is_a?(Hash)
@@ -83,18 +87,38 @@ RgGen.define_simple_feature(:bit_field, :bit_assignment) do
83
87
 
84
88
  def parse_value(input_value, key)
85
89
  input_value.key?(key) &&
86
- instance_variable_set("@#{key}", Integer(input_value[key]))
90
+ instance_variable_set(VARIABLE_NAMES[key], Integer(input_value[key]))
87
91
  rescue ArgumentError, TypeError
88
92
  error "cannot convert #{input_value[key].inspect} into " \
89
93
  "bit assignment(#{key.to_s.tr('_', ' ')})"
90
94
  end
91
95
 
96
+ def lsb_base
97
+ @lsb_base ||=
98
+ ((bit_field.component_index.zero? && 0) || calc_next_lsb(previous_bit_field))
99
+ end
100
+
101
+ def previous_bit_field
102
+ index = bit_field.component_index - 1
103
+ bit_fields[index]
104
+ end
105
+
106
+ def calc_next_lsb(bit_field)
107
+ compact_sequential_bit_field?(bit_field) &&
108
+ (bit_field.lsb + bit_field.width * bit_field.sequence_size) ||
109
+ (bit_field.lsb + bit_field.width)
110
+ end
111
+
112
+ def compact_sequential_bit_field?(bit_field)
113
+ bit_field.sequential? && (bit_field.step == bit_field.width)
114
+ end
115
+
92
116
  def lsb_bit(index = 0)
93
- lsb_msb_bit(index, @lsb)
117
+ lsb_msb_bit(index, lsb_base)
94
118
  end
95
119
 
96
120
  def msb_bit(index = 0)
97
- lsb_msb_bit(index, @lsb + width - 1)
121
+ lsb_msb_bit(index, lsb_base + width - 1)
98
122
  end
99
123
 
100
124
  def lsb_msb_bit(index, base)
@@ -114,9 +138,7 @@ RgGen.define_simple_feature(:bit_field, :bit_assignment) do
114
138
  end
115
139
 
116
140
  def overlap?
117
- register
118
- .bit_fields
119
- .any? { |bit_field| (bit_field.bit_map & bit_map).nonzero? }
141
+ bit_fields.any? { |bit_field| (bit_field.bit_map & bit_map).nonzero? }
120
142
  end
121
143
  end
122
144
  end
@@ -2,16 +2,35 @@
2
2
 
3
3
  RgGen.define_simple_feature(:bit_field, :initial_value) do
4
4
  register_map do
5
- property :initial_value, default: 0
6
- property :initial_value?, body: -> { !@initial_value.nil? }
5
+ property :initial_value
6
+ property :initial_values
7
+ property :initial_value?, forward_to: :initial_value_set?
8
+ property :fixed_initial_value?, forward_to: :fixed?
9
+ property :initial_value_array?, forward_to: :array?
10
+
11
+ input_pattern [{ parameterized: /default:(#{integer})/,
12
+ array: /#{integer}(?:[,\n]#{integer})+/ }]
7
13
 
8
14
  build do |value|
9
- @initial_value =
10
- begin
11
- Integer(value)
12
- rescue ArgumentError, TypeError
13
- error "cannot convert #{value.inspect} into initial value"
15
+ @input_format =
16
+ if value.is_a?(Hash) || match_index == :parameterized
17
+ :parameterized
18
+ elsif value.is_a?(Array) || match_index == :array
19
+ :array
20
+ else
21
+ :single
14
22
  end
23
+ @initial_value, @initial_values = parse_initial_value(value)
24
+ end
25
+
26
+ define_helpers do
27
+ def verify_initial_value(&block)
28
+ initial_value_verifiers << create_verifier(&block)
29
+ end
30
+
31
+ def initial_value_verifiers
32
+ @initial_value_verifiers ||= []
33
+ end
15
34
  end
16
35
 
17
36
  verify(:component) do
@@ -20,40 +39,130 @@ RgGen.define_simple_feature(:bit_field, :initial_value) do
20
39
  end
21
40
 
22
41
  verify(:component) do
23
- error_condition { initial_value? && initial_value < min_initial_value }
42
+ error_condition do
43
+ @input_format == :array && !bit_field.sequential?
44
+ end
24
45
  message do
25
- 'input initial value is less than minimum initial value: ' \
26
- "initial value #{initial_value} " \
27
- "minimum initial value #{min_initial_value}"
46
+ 'arrayed initial value is not allowed for non sequential bit field'
28
47
  end
29
48
  end
30
49
 
31
50
  verify(:component) do
32
- error_condition { initial_value? && initial_value > max_initial_value }
33
- message do
34
- 'input initial value is greater than maximum initial value: ' \
35
- "initial value #{initial_value} " \
36
- "maximum initial value #{max_initial_value}"
51
+ error_condition do
52
+ @input_format == :array && initial_values.size > bit_field.sequence_size
37
53
  end
54
+ message { 'too many initial values are given' }
38
55
  end
39
56
 
40
57
  verify(:component) do
41
- error_condition { initial_value? && !match_valid_condition? }
42
- message do
43
- "does not match the valid initial value condition: #{initial_value}"
58
+ error_condition do
59
+ @input_format == :array && initial_values.size < bit_field.sequence_size
60
+ end
61
+ message { 'few initial values are given' }
62
+ end
63
+
64
+ verify(:component) do
65
+ check_error do
66
+ Array(initial_value || initial_values)
67
+ .each(&method(:verify_initial_value))
68
+ end
69
+ end
70
+
71
+ verify_initial_value do
72
+ error_condition { |value| value < min_initial_value }
73
+ message do |value|
74
+ 'input initial value is less than minimum initial value: ' \
75
+ "initial value #{value} minimum initial value #{min_initial_value}"
76
+ end
77
+ end
78
+
79
+ verify_initial_value do
80
+ error_condition { |value| value > max_initial_value }
81
+ message do |value|
82
+ 'input initial value is greater than maximum initial value: ' \
83
+ "initial value #{value} maximum initial value #{max_initial_value}"
84
+ end
85
+ end
86
+
87
+ verify_initial_value do
88
+ error_condition { |value| !match_valid_condition?(value) }
89
+ message do |value|
90
+ "does not match the valid initial value condition: #{value}"
44
91
  end
45
92
  end
46
93
 
47
94
  printable(:initial_value) do
48
- @initial_value &&
49
- begin
50
- print_width = (bit_field.width + 3) / 4
51
- format('0x%0*x', print_width, @initial_value)
52
- end
95
+ if @input_format == :parameterized
96
+ "default: #{format_value(initial_value)}"
97
+ elsif @input_format == :array
98
+ initial_values.map(&method(:format_value))
99
+ elsif initial_value?
100
+ format_value(initial_value)
101
+ end
53
102
  end
54
103
 
55
104
  private
56
105
 
106
+ def initial_value_format
107
+ @initial_value_format ||=
108
+ if @input_format == :parameterized
109
+ bit_field.sequential? && :array || :single
110
+ else
111
+ @input_format
112
+ end
113
+ end
114
+
115
+ def array?
116
+ initial_value_format == :array
117
+ end
118
+
119
+ def fixed?
120
+ [:array, :single].include?(@input_format)
121
+ end
122
+
123
+ def parse_initial_value(input_value)
124
+ if @input_format == :parameterized
125
+ [parse_parameterized_initial_value(input_value), nil]
126
+ elsif @input_format == :array
127
+ [nil, parse_arrayed_initial_value(input_value)]
128
+ else
129
+ [parse_value(input_value), nil]
130
+ end
131
+ end
132
+
133
+ def parse_parameterized_initial_value(input_value)
134
+ value =
135
+ if pattern_matched?
136
+ match_data.captures.first
137
+ else
138
+ input_value
139
+ .fetch(:default) { error 'no default value is given' }
140
+ end
141
+ parse_value(value)
142
+ end
143
+
144
+ def parse_arrayed_initial_value(input_value)
145
+ values =
146
+ if pattern_matched?
147
+ input_value.split(/[,\n]/)
148
+ else
149
+ input_value
150
+ end
151
+ values.map(&method(:parse_value))
152
+ end
153
+
154
+ def parse_value(value)
155
+ Integer(value)
156
+ rescue ArgumentError, TypeError
157
+ error "cannot convert #{value.inspect} into initial value"
158
+ end
159
+
160
+ def verify_initial_value(value)
161
+ helper.initial_value_verifiers.each do |verifier|
162
+ verifier.verify(self, value)
163
+ end
164
+ end
165
+
57
166
  def settings
58
167
  @settings ||=
59
168
  (bit_field.settings && bit_field.settings[:initial_value]) || {}
@@ -67,9 +176,18 @@ RgGen.define_simple_feature(:bit_field, :initial_value) do
67
176
  2**bit_field.width - 1
68
177
  end
69
178
 
70
- def match_valid_condition?
179
+ def match_valid_condition?(value)
71
180
  !settings.key?(:valid_condition) ||
72
- instance_exec(@initial_value, &settings[:valid_condition])
181
+ instance_exec(value, &settings[:valid_condition])
182
+ end
183
+
184
+ def initial_value_set?
185
+ [@initial_value, @initial_values].any?
186
+ end
187
+
188
+ def format_value(value)
189
+ print_width = (bit_field.width + 3) / 4
190
+ format('0x%0*x', print_width, value)
73
191
  end
74
192
  end
75
193
  end
@@ -2,19 +2,15 @@
2
2
 
3
3
  RgGen.define_simple_feature(:bit_field, :name) do
4
4
  register_map do
5
- property :name, initial: -> { register.name }
5
+ property :name, default: -> { register.name }
6
6
  property :full_name, forward_to: :get_full_name
7
7
 
8
8
  input_pattern variable_name
9
9
 
10
10
  build do |value|
11
- @name =
12
- if pattern_matched?
13
- match_data.to_s
14
- else
15
- error "illegal input value for bit field name: #{value.inspect}"
16
- end
17
- @full_name = [register.name, @name]
11
+ pattern_matched? ||
12
+ (error "illegal input value for bit field name: #{value.inspect}")
13
+ @name = match_data.to_s
18
14
  end
19
15
 
20
16
  verify(:feature) do
@@ -22,16 +18,19 @@ RgGen.define_simple_feature(:bit_field, :name) do
22
18
  message { "duplicated bit field name: #{name}" }
23
19
  end
24
20
 
25
- printable :name
21
+ printable(:name) do
22
+ RgGen::Core::Utility::CodeUtility
23
+ .array_name(name, Array(bit_field.sequence_size))
24
+ end
26
25
 
27
26
  private
28
27
 
29
28
  def get_full_name(separator = '.')
30
- @full_name&.join(separator) || register.name
29
+ [register.full_name(separator), *@name].join(separator)
31
30
  end
32
31
 
33
32
  def duplicated_name?
34
- register.bit_fields.any? { |bit_field| bit_field.name == name }
33
+ bit_fields.any? { |bit_field| bit_field.name == name }
35
34
  end
36
35
  end
37
36
  end
@@ -7,18 +7,12 @@ RgGen.define_simple_feature(:bit_field, :reference) do
7
7
  property :reference_width, forward_to: :required_width
8
8
  property :find_reference, forward_to: :find_reference_bit_field
9
9
 
10
- input_pattern [
11
- /(#{variable_name})\.(#{variable_name})/,
12
- /(#{variable_name})/
13
- ]
10
+ input_pattern /(#{variable_name}(?:\.#{variable_name})*)/
14
11
 
15
12
  build do |value|
16
- @input_reference =
17
- if pattern_matched?
18
- match_data[1..2].compact.join('.')
19
- else
20
- error "illegal input value for reference: #{value.inspect}"
21
- end
13
+ pattern_matched? ||
14
+ (error "illegal input value for reference: #{value.inspect}")
15
+ @input_reference = match_data.to_s
22
16
  end
23
17
 
24
18
  verify(:component) do
@@ -38,20 +32,46 @@ RgGen.define_simple_feature(:bit_field, :reference) do
38
32
 
39
33
  verify(:all) do
40
34
  error_condition do
41
- reference? && !register.array? && reference_bit_field.register.array?
35
+ reference? && within_array?(reference_bit_field) &&
36
+ (bit_field.depth != reference_bit_field.depth)
42
37
  end
43
38
  message do
44
- 'bit field of array register is not allowed for ' \
45
- "reference bit field: #{@input_reference}"
39
+ 'depth of layer is not matched: ' \
40
+ "own #{bit_field.depth} " \
41
+ "reference #{reference_bit_field.depth}"
42
+ end
43
+ end
44
+
45
+ define_helpers do
46
+ def verify_array(&block)
47
+ array_verifiers << create_verifier(&block)
48
+ end
49
+
50
+ def array_verifiers
51
+ @array_verifiers ||= []
46
52
  end
47
53
  end
48
54
 
49
55
  verify(:all) do
50
- error_condition { reference? && !match_array_size? }
51
- message do
56
+ check_error do
57
+ reference? && within_array?(reference_bit_field) &&
58
+ helper.array_verifiers.each(&method(:verify_array))
59
+ end
60
+ end
61
+
62
+ verify_array do
63
+ error_condition { |own, ref| !own.array? && ref.array? }
64
+ message do |*_, layer|
65
+ "bit field within array #{layer.to_s.tr('_', ' ')} is not allowed for " \
66
+ "reference bit field: #{@input_reference}"
67
+ end
68
+ end
69
+
70
+ verify_array do
71
+ error_condition { |own, ref| unmatch_array_size?(own, ref) }
72
+ message do |own, ref|
52
73
  'array size is not matched: ' \
53
- "own #{register.array_size} " \
54
- "reference #{reference_bit_field.register.array_size}"
74
+ "own #{own.array_size} reference #{ref.array_size}"
55
75
  end
56
76
  end
57
77
 
@@ -66,7 +86,7 @@ RgGen.define_simple_feature(:bit_field, :reference) do
66
86
  end
67
87
 
68
88
  verify(:all) do
69
- error_condition { reference? && !match_sequence_size? }
89
+ error_condition { reference? && unmatch_sequence_size? }
70
90
  message do
71
91
  'sequence size is not matched: ' \
72
92
  "own #{bit_field.sequence_size} " \
@@ -125,14 +145,23 @@ RgGen.define_simple_feature(:bit_field, :reference) do
125
145
  find_reference_bit_field(register_block.bit_fields)
126
146
  end
127
147
 
128
- def match_array_size?
129
- !(register.array? && reference_bit_field.register.array?) ||
130
- register.array_size == reference_bit_field.register.array_size
148
+ def within_array?(bit_field)
149
+ bit_field.register_files.any?(&:array?) || bit_field.register.array?
150
+ end
151
+
152
+ def verify_array(verifier)
153
+ [*register_files, register]
154
+ .zip([*reference_bit_field.register_files, reference_bit_field.register])
155
+ .each { |own, ref| verifier.verify(self, own, ref, own.layer) }
156
+ end
157
+
158
+ def unmatch_array_size?(own, ref)
159
+ own.array? && ref.array? && own.array_size != ref.array_size
131
160
  end
132
161
 
133
- def match_sequence_size?
134
- !(bit_field.sequential? && reference_bit_field.sequential?) ||
135
- bit_field.sequence_size == reference_bit_field.sequence_size
162
+ def unmatch_sequence_size?
163
+ bit_field.sequential? && reference_bit_field.sequential? &&
164
+ (bit_field.sequence_size != reference_bit_field.sequence_size)
136
165
  end
137
166
 
138
167
  def required_width