Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VHDL shift_right shift amount must be a natural: #1810

Closed
christiaanb opened this issue May 16, 2021 · 2 comments · Fixed by #1825
Closed

VHDL shift_right shift amount must be a natural: #1810

christiaanb opened this issue May 16, 2021 · 2 comments · Fixed by #1825
Assignees
Labels

Comments

@christiaanb
Copy link
Member

christiaanb commented May 16, 2021

As can be seen on https://groups.google.com/g/clash-language/c/CQTJhkDrb1Q/m/6YcY0Ur-AAAJ GHDL raises an error when the shift amount to the shift_right call is a negative number. As we can see in:

https://github.com/ghdl/ghdl/blob/c2b3f93dfa40ee92de53b54e38e1819cfc33cb04/libraries/ieee/numeric_std.vhdl#L556-L560

  -- Id: S.2
  function SHIFT_RIGHT (ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED;
  -- Result subtype: UNSIGNED(ARG'LENGTH-1 downto 0)
  -- Result: Performs a shift-right on an UNSIGNED vector COUNT times.
  --         The vacated positions are filled with '0'.
  --         The COUNT rightmost elements are lost.

and

https://github.com/ghdl/ghdl/blob/c2b3f93dfa40ee92de53b54e38e1819cfc33cb04/libraries/ieee/numeric_std.vhdl#L570-L574

  function SHIFT_RIGHT (ARG: SIGNED; COUNT: NATURAL) return SIGNED;
  -- Result subtype: SIGNED(ARG'LENGTH-1 downto 0)
  -- Result: Performs a shift-right on a SIGNED vector COUNT times.
  --         The vacated positions are filled with the leftmost
  --         element, ARG'LEFT. The COUNT rightmost elements are lost.

the shift count must be a natural number.

However, the default implementation for the shift method of the Bits class is: http://hackage.haskell.org/package/base-4.14.1.0/docs/src/Data.Bits.html#shift

    x `shift`   i | i<0       = x `shiftR` (-i)
                  | i>0       = x `shiftL` i
                  | otherwise = x

which gets translated to concurrent assignments by clash, i.e. that shift method will get translated to something like the following VHDL:

alt1 <= shift_right(x,-i);
alt2 <= shift_left(x,i);
res <= alt1 when (i < 0) else
       alt2 when (i > 0) else
       x;

The solution is to create primitives for the shift instance methods which we can control: Signed, Unsigned, Bit and BitVector; so that we can generate the following VHDL instead:

process (x,i) begin
  if (i < 0) then
    res <= shift_right(x,-i);
  elsif (i > 0) then
    res <= shift_left(x,i)
  else
    res <= x;
  end if;
end;

ensuring that the shift_right is not evaluated concurrently to the shift_left when i > 0.

@christiaanb
Copy link
Member Author

christiaanb commented May 16, 2021

Another option is to translate shiftR to:

res <= shift_right(x,i)
-- pragma translate_off
          when (i >= 0) else shift_left(x,-i)
-- pragma translate_on
          ;

so that we only get a shift_right for synthesis, but no errors during simulation. This is probably the thing we'll need to do for the shiftR primitives for the Int, Word, Integer, etc. types.

@alex-mckenna alex-mckenna self-assigned this May 17, 2021
@alex-mckenna
Copy link
Contributor

Same applies to rotate:

function ROTATE_LEFT (ARG: SIGNED; COUNT: NATURAL) return SIGNED;
x `rotate`  i | i<0       = x `rotateR` (-i)
              | i>0       = x `rotateL` i
              | otherwise = x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants