IEEE 200X Fast Track Change Proposal ID: FT-20 Owner: John Ries email: Status: Proposed: 1/04 Updated 3/21/05 Analyzed: Date Resolved: Date Enhancement Summary: Permit concatenation on LHS of an expression Relevant LRM section 7.3.2.2, 8.4, 8.5 Related issues: Relevant LRM section: Enhancement Detail: ---------------------------- Initial proposal was to use concatenation on the LHS. Like CarryOut & Result <= ('0'&A) + ('0'&B) ; The proposal has been modified to allow aggregates to have choices that are vectors so that you can do ( CarryOut, Result) <= ('0' & A) + ( '0' & B); or (CarryOut, Result) <= ( '0', A) + ('0', B); Analysis: ---------------------------- Modifications to 1076-2002 The group has decide to use a modified aggregate form to get the desired behavior instead of allowing left hand side concatenation. The main reason is that & on the left of an operator would be different than the & used in expressions and would not be overloadable. This is thought to be confusing. The modification to aggregates is to allow the expressions of an element association in an array aggregate be of the same type as the aggregate itself. Therefore, for an array aggregate of a one-dimensional array type, each element association expression must be either of that array's element type or the array type itself. For example an aggregate of std_logic_vector, the element association expression must either be of std_ulogic or std_logic_vector type. If the element association expression's type is an array type then the element association must either not have a choice or the choice must be a discrete range. If no choice is present, then the expression specifies the next N elements of the association, where N is the expression's length. If the choice is a discrete range, then the size of the discrete range and the size of the element association's expression must be the same. Each element of the element association's expression corresponds to the matching index value enumerated by the discrete range. In effect the association 0 to 3 => s(1 to 4) is the same as saying 0 => s(1), 1=>s(2), 2=>s(3), 3=>s(4). Note that the choice range's directions and bounds do not have to match the actual expressions bounds. The left most choice index is matched to the left most element of the expression. The next left most choice index matches the next left most element and so forth. This requirements that for each index specified in the choice range there is a matching element in the expression. There are two issues to address, direction of ranges and backward compatibility. Currently the direction of the discrete range does not have any impact on the aggregate's direction. The direction of an aggregate is either determined from context or from the aggregate's base type index constraint. Call not changing this option 1. In option 1, if the element association's expression is of the aggregate's type then it is expanded into N element associations for each element in the expression. (See above). The direction and bounds of the aggregate is then determined using the rules in section 7.3.2.2. For example: Example A: SUBTYPE nibble : STD_LOGIC_VECTOR(3 down to 0); VARIABLE v1 : nibble := "0011"; VARIABLE v2 : nibble; ... v2 := (0 to 3 => v1); -- same as v2 := nibble'(0=>v1(3), 1=>v1(2), -- 2=>v1(1), 3=>v1(0)); -- which is the same as -- v2(3) := v1(0); -- v2(2) := v1(1); -- v2(1) := v1(2); -- v2(0) != v1(3); -- in effect v2 is the reverse of v1. In example A, using the discrete range 0 to 3 instead of 3 down to 0 has the in effect of swapping the bits of V1 when assigned to V2. If the range 7 down to 4 was used the bits of V1 would not be swapped, because the only the direction is taken from v2. Not the actual bounds. The disadvantage of this option is the direction of an aggregate is defined in section 7.3.2.2 and have a number of quirks. Take the following examples: Example B1: VARIABLE v2 : nibble := ( 0 to 3 => v1); -- reverses because of item e in 7.3.2.2 -- specifies that the range on the aggregate is -- 3 down to 0 from v2's subtype. v2 := ( 0 to 3 => v1(3 downto 0)) & "1110"; -- same as -- v2(3) := v1(3) & '1'; -- v2(2) := v1(2) & '1'; -- v2(1) := v1(1) & '1'; -- v2(0) := v1(0) & '1'; -- because direction of aggregate is taken -- from the base type's direction One thing to be aware of is that aggregates on the left side always get their direction from the index constraint of the base type. For all practical purposes the aggregates on the left have the direction TO. This isn't a problem for positional aggregates: ( cout, sum(2 downto 0)) := V1 + V2; But for named aggregates like ( 3 => cout , 2 downto 0 =>sum(2 downto 0) ) <= V1 + V2; actually is the same as ( sum(0), sum(1), sum(2), cout) <= V1 + V2; It is this fact that the user can't control the direction of the aggregate that cause confusion with this option. Adding a rule to take the direction of the subtype of the right hand expression doesn't do much good because most expressions don't have a subtype. In the other option, Option 2, use the direction of the discrete range to determined by the direction of the aggregate's range. If the direction determined by context in section 7.3.2.2 differs from the element association direction, an error occurs. This would remove the possibility of bit swapping. Example A would now be illegal because the range 0 to 3 had a different direction from that of aggregate's subtype that is downto. The range direction would only be used in the case where the expression is not the element type. Examples comparing option 1 and 2. Example C: v2 := ( 0 to 3 => '1') -- legal in both Option 1 and 2. -- would be v2 := ( '0', '1', '2', '3' => '1') -- would be v2 := "1111"; Example D: v2 := ( 0 to 3 => v1) -- Option 2 would produce an error, the aggregate -- has the bounds 3 downto 0. -- Option 1 would be the same as -- v2 := ( 0 => v1(3), 1 => v1(2), 2 => v1(1), 3 =>v1(0)); -- which is the same as -- v2(3) := v1(0); v2(2) := v1(1); v2(1) := v1(2); -- v2(0) := v1(3); Example E: v2 := ( 3 downto 0 => v1 ) -- Option 1 and 2 are both legal -- same as -- v2 := ( 3 => v1(3), 2 => v1(2), 1 => v1(1), 0 =>v1(0)); -- same as v2(3) <= v1(3); v2(2) <= v1(2); -- v2(1) <= v1(1); v2(0)<=v1(0); Example F: variable x : nibble := ( 0 to 3 => v1 ) -- Illegal in option 2 because the -- subtype of the aggregate is -- nibble(LRM 7.3.2.2) and the direction -- of range is wrong direction. -- Legal option 1, bits are swapped. Example G: v2 := ( 0 to 1 => "10", 3 downto 2 => "10") -- legal option 1 same -- as (0 => '1', 1=>'0', -- 2 => '0', 3=>'1') -- v2 := "1001"; -- illegal option 2 because -- of mixed directions Example H: v2 := ( 0 to 1 => '1', 3 downto 2 => '0') -- legal in both, element type -- "0011" is the resulting value Example I: v2 := ( 0 to 1 => v1(3 downto 2), 3 downto 2 => '1') -- illegal option 2 -- option 1 is equivalent to -- v2 := "11" & v1(2) & v(3); Example J: ( cout, sum ) := A + B; -- legal in both options Example K (3=>cout, 2 downto 0 => sum) := A+B; -- legal in both but produces different results -- option 2 is the same as -- ( cout, sum(2), sum(1), sum(0) ) := A+B; -- option 1 is the same as -- (sum(0), sum(1), sum(2), cout) := A +B; Example L result := A + (3=>cout, 2 downto 0 => sum); -- legal in both but produces different results -- option 2 is A+ ( cin & sum); -- option 1 is A+(sum(0),sum(1),sum(3),cin) Example M result := A + (3=>cout, 2 downto 0 => 0); -- legal in both but produces same results -- option 1&2 is A+ ( "000" & cin); The other problem is a backward compatibility problem. The following example show a case where an expression would now be ambiguous. Example N: FUNCTION f RETURN BIT IS BEGIN RETURN '1'; END; FUNCTION f RETURN BIT_VECTOR IS BEGIN RETURN "01"; END; VARIBLE l : BIT_VECTOR(1 DOWNTO 0) ; ... l := ( 0 to 1 => f); -- In 2002 and earlier F must be of bit type -- so l will be "11". -- With this change F may be bit or bit_vector. -- Since both exist, the expression is ambiguous. y := ( '1', f); -- also ambiguous In order to have backward compatibility, it would require adding a rule for overloading stating that if the expression of an element association is ambiguous, but not ambiguous if the element type of the aggregate is used, then the element type is required. The drawback is that overloading is slightly more complicated in an end case. From meeting discussions, the conclusion is to use option 2 and not be backward compatible. It is thought that this is a very rare case. Resolution: ---------------------------- [To be performed by the 200X Fast Track Working Group]