Vhdl, is there a way, to use modulo on larger than 64 bits unsigned? - vhdl

I've got two 115bits unsigned vectors. I have to do some mod calculations on them, but Quartus shows those errors.
Error: In lpm_divide megafunction, LPM_WIDTHN must be less than or equals to 64
Error: In lpm_divide megafunction, LPM_WIDTHD must be less than or equal to 64
Error: Can't elaborate inferred hierarchy "lpm_divide:Mod0"
I fully understand, that numbers are too large to perform mod. Is there a way/library/any idea how to solve this problem? I would love to avoid using any "substracting loop", and be as simple as possible. VHDL is not my world, and after academic project I will abandon it with pleasure :P
Application has to calculate modulo inversion. As far as I am not master from VHDL, I've tried doing it using fast powering + mod alghoritm. Application can sucks, it just has to work :d
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use IEEE.std_logic_unsigned.all;
library altera;
use altera.altera_primitives_components.all;
entity inwersja is
port(
a: in unsigned(114 downto 0);
clk: in std_logic;
start: in std_logic;
reset: in std_logic;
c: out unsigned(114 downto 0);
ready: out std_logic);
end inwersja;
architecture i1 of inwersja is
begin
process(clk)
variable tempOutput : unsigned(114 downto 0) := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001";
variable temp : unsigned (114 downto 0):= a;
variable modul: unsigned(114 downto 0) := "1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101011";
variable power: unsigned(114 downto 0) := "1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101001";
variable counter: integer := 0;
begin
if reset='1' then
tempOutput := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001";
ready <= '0';
elsif clk'event and clk='1' then
if start='0' then
ready<='0';
else
if (counter < 115) then
if (power(counter) /= '0') then
tempOutput := (tempOutput * temp) mod modul;
end if;
temp := (temp * temp) mod modul;
counter := counter + 1;
elsif (counter = 115) then
ready <= '1';
end if;
end if;
end if;
c <= tempOutput;
end process;
end i1;

Related

VHDL : Internal signals are undefined even when defined in the architecture declaration section

So I've been working on some homework for my VHDL course and I can't seem to understand this problem.
The point here is to create the adder/subtractor of an ALU that works both on 2's complement and unsigned 32-bit buses, which is why I have a condition called sub_mode ( A - B = A + !B + 1 ) which will also be the carry-in when activated.
The rest of the different inputs and outputs are pretty self-explanatory.
My problem is with the testbenching of such component where, even though carry_temp and r_temp have been initialized in declaration section of the architecture, end up showing up undefined. I have guessed that it is due to the for loop within the process screwing everything up. Would that be an accurate guess? And if yes, is it possible to proceed to add two bit buses together without having to fully create an n-bit adder made from n 1-bit adder components?
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity add_sub is
port(
a : in std_logic_vector(31 downto 0);
b : in std_logic_vector(31 downto 0);
sub_mode : in std_logic;
carry : out std_logic;
zero : out std_logic;
r : out std_logic_vector(31 downto 0)
);
end add_sub;
architecture synth of add_sub is
signal cond_inv : std_logic_vector(31 downto 0);
signal carry_temp : std_logic_vector(32 downto 0) := (others => '0');
signal r_temp : std_logic_vector(31 downto 0) := (others => '0');
begin
behave : process(a,b,sub_mode)
begin
if sub_mode = '1' then
cond_inv <= b xor x"ffffffff";
else
cond_inv <= b;
end if;
carry_temp(0) <= sub_mode;
for i in 0 to 31 loop
r_temp(i) <= a(i) xor cond_inv(i) xor carry_temp(i);
carry_temp(i+1) <=
(a(i) and cond_inv(i)) or
(a(i) and carry_temp(i)) or
(cond_inv(i)and carry_temp(i));
end loop;
if r_temp = x"00000000" then
zero <= '1';
else
zero <= '0';
end if;
r <= r_temp;
carry <= carry_temp(32);
end process behave;
end synth;

Non-static loop limit exceeded in Xilinx

I have this code in VHDL:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.NUMERIC_STD.all;
entity Div is
Port ( Ain : in STD_LOGIC_VECTOR (6 downto 0);
Bin : in STD_LOGIC_VECTOR (6 downto 0);
Q : out STD_LOGIC_VECTOR (6 downto 0);
R : out STD_LOGIC_VECTOR (6 downto 0)
Rez : out std_logic_vector(13 downto 0));
end Div;
architecture Behavioral of Div is
begin
Proc1 : process (Ain, Bin) is
variable cnt : std_logic_vector(6 downto 0);
variable Atemp : std_logic_vector(6 downto 0);
begin
if (Ain < Bin) then
cnt := "0000000";
Atemp := Ain;
elsif (Ain = Bin) then
cnt := "0000001";
Atemp := (others => '0');
elsif (Ain > Bin) then
cnt := "0000001";
Atemp := (Ain - Bin);
while (Atemp >= Bin) loop
Atemp := (Atemp - Bin);
cnt := cnt + "0000001";
end loop;
end if;
Q <= cnt;
R <= Atemp;
Rez <= "0000000" & cnt;
end process Proc1;
end Behavioral;
and when I synt in Xilinx, I have this error message
Non-static loop limit exceeded
at that while loop.
When VHDL is synthesised, the synth tool needs to unwrap your loop to create a circuit. Because it has no idea what the Atemp or Bin are, other than they are 7 bit integers, it has to assume that Atemp and Bin could be static forever, and hence the loop never unrolls.
The problem with your code is that you used a while loop. Your HDL needs to describe a circuit, and a while loop generally doesn't. Instead of using a while loop, consider using a clock in your process and incrementing the counter by 1 on each clock. Circuits have no knowledge of time without a clock.

How to use the Xilinx Division IP Core

I am writing code in VHDL to be synthesised onto a XilinX FPGA. I typically use GHDL to simulate my testbenches. I need to make use of the XilinX division core in order to divide by a variable however I am not sure how to do this as there appear to be no examples in the XilinX documentation. Do I have to use the XilinX software to generate the VHDL component for the divider? Or does XilinX implicitly understand that divider means using the IP core? If my 2nd statement is true how would I go about simulating this with GHDL or would I have to use a XilinX simulation tool? I could really do with a minimal example of using the XilinX divider core to implement division by a variable e.g. something like this:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
entity DividingExample is
port (
clk : in std_logic;
reset : in std_logic;
InputSignal : in std_logic_vector(15 downto 0);
OutputSignal : out std_logic_vector(15 downto 0)
);
end DividingExample;
architecture behaviour of DividingExample is
-- declarations
signal numerator : integer;
begin
-- behaviour
process(clk)
begin
if(rising_edge(clk)) then
if(reset = '1') then
-- reset values
numerator <= 1000;
else
-- calculate value to be output
OutputSignal <= numerator/to_integer(signed(InputSignal))
end if;
end if;
end process;
end behaviour;
This example code obviously doesn't work as division (the '/' operator) is not defined for the integer datatype. How might I go about this?
I ended up writing my own division code, which was significantly quicker and easier to implement than using XilinX's IP Core. I used the binary division algorithm detailed here and wrote the following VHDL code for a signed 32 bit division:
function Divide(N : signed(31 downto 0); D : signed(31 downto 0)) return signed is
variable Q : signed(31 downto 0) := to_signed(0, 32);
variable R : signed(31 downto 0) := to_signed(0, 32);
variable l : line;
constant N_Abs : signed(31 downto 0) := abs(N);
constant D_Abs : signed(31 downto 0) := abs(D);
begin
-- behaviour
for i in N_Abs'high downto 0 loop
R := shift_left(R, 1);
R(0) := N_Abs(i);
if R >= D_Abs then
R := R - D;
Q(i) := '1';
end if;
end loop;
if ((N < 0 and D > 0) or (N > 0 and D < 0)) then
return -Q;
else
return Q;
end if;
end function;

Self implemented UART in VHDL always skips second character

I am learning VHDL right now and I tried to implement UART (1 start bit, 8 data bits, 1 stop bit) to periodically send a hardcoded string.
Everything works as expected - I receive string every 1 second. However, there is no second character.
No matter how long the string is, which character it is. I checked this fact on a oscilloscope and there is no waveform for this particular character. 1 start bit, 8 bits for first character, stop bit, start bit and 8 bits for third character, not the second one.
Following code is for 10 MHz clock divided to send with ~38 400 bits per second, I also tried with 9600 bits per second, both the same problem.
I'm using Altera MAX10 dev board: http://maximator-fpga.org/
Short video how it works:
https://gfycat.com/JoyousIlliterateGuillemot
UART.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.ALL;
use ieee.std_logic_arith.all;
entity UART is
port (
clk_10mhz: in STD_LOGIC;
txPin: out STD_LOGIC
);
end entity;
architecture Test of UART is
signal txStart: STD_LOGIC;
signal txIdle: STD_LOGIC;
signal txData: STD_LOGIC_VECTOR(7 downto 0);
component TX is
port (
clk_in: in STD_LOGIC;
start: in STD_LOGIC;
data: in STD_LOGIC_VECTOR(7 downto 0);
tx: out STD_LOGIC;
txIdle: out STD_LOGIC
);
end component TX;
begin
process (clk_10mhz, txIdle)
variable clkDividerCounter : integer range 0 to 10000000;
variable textToSend : string(1 to 31) := "Hello darkness my old friend!" & CR & LF;
variable currentCharacterIndex : integer range 0 to 31;
begin
if (rising_edge(clk_10mhz)) then
if (clkDividerCounter < 10000000) then
clkDividerCounter := clkDividerCounter + 1;
else
clkDividerCounter := 0;
currentCharacterIndex := 1;
end if;
if (txIdle = '1' and currentCharacterIndex > 0) then
txData <= CONV_STD_LOGIC_VECTOR(character'pos(textToSend(currentCharacterIndex)),8);
txStart <= '1';
if (currentCharacterIndex < 31) then
currentCharacterIndex := currentCharacterIndex + 1;
else
currentCharacterIndex := 0;
txStart <= '0';
end if;
end if;
end if;
end process;
u1: TX port map (clk_10mhz, txStart, txData, txPin, txIdle);
end Test;
TX.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.ALL;
entity TX is
port (
clk_in: in STD_LOGIC;
start: in STD_LOGIC;
data: in STD_LOGIC_VECTOR(7 downto 0);
tx: out STD_LOGIC;
txIdle: out STD_LOGIC
);
end entity;
architecture Test of TX is
signal idle: STD_LOGIC;
begin
process (clk_in)
variable bitIndex : integer range 0 to 9;
variable clkDividerCounter : integer range 0 to 260;
variable dataFrame : STD_LOGIC_VECTOR(9 downto 0);
variable dataFrameCurrentIndex : integer range 0 to 9;
begin
if (rising_edge(clk_in)) then
if (start = '1' and idle = '1') then
dataFrame(0) := '0';
dataFrame(8 downto 1) := data;
dataFrame(9) := '1';
dataFrameCurrentIndex := 0;
idle <= '0';
end if;
if (idle = '0') then
if (clkDividerCounter < 260) then
clkDividerCounter := clkDividerCounter + 1;
else
if (dataFrameCurrentIndex <= 9) then
tx <= dataFrame(dataFrameCurrentIndex);
dataFrameCurrentIndex := dataFrameCurrentIndex + 1;
else
idle <= '1';
end if;
clkDividerCounter := 0;
end if;
end if;
txIdle <= idle;
end if;
end process;
end Test;
Move the line
txIdle <= idle;
from TX.vhd outside the process. Signals take their new value after the process ends.
For example:
idle <= '0';
txIdle <= idle;
Will set txIdle to '1' if idle was '1' when the two statements were executed inside a process. You should notice that this means that txIdle will be '1' for two consecutive cycles and causes currentCharacterIndex to increment twice at the start.
Note that contrary to signals, variable take their new value when the assigning statement is encountered, and not at the end of the process as signals do.
While your code is not that terrible for a beginner, I recommend to use only signal when you start learning VHDL. It is much easier to make mistake with variables, or describe sub-optimal or broken implementation.
Also, as Brian mentioned, don't use std_logic_arith, especially when using numeric_std. They are conflicting with each other (some tools deal with it though) and std_logic_arith is not a IEEE standard, while numeric_std is.
Finally, simulation is a crucial part of hardware design. To avoid uninitialized pin, add a reset to your circuit, which is generally a good idea.

I am trying to implement a 1-2-3-4-6 counter in VHDL but the count is incrementing form 1-7 .

This is a VHDL code to count in sequence 1-2-3-4-6-7 but seems to count form 1-7
The code seems to have a logical error somewhere . Please help
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity newtest is
port(C, CLR : in std_logic;
Q : out std_logic_vector(2 downto 0));
end newtest;
architecture archi of newtest is
signal tmp: std_logic_vector(2 downto 0);
begin
process (C, CLR)
begin
if (CLR='1') then
tmp <= "000";
elsif (C'event and C='1') then
if (tmp="100") then
tmp <= tmp + 1;
end if;
tmp <= tmp + 1;
end if;
end process;
Q <= tmp;
end archi;
In a process with two sequential signal assignments to tmp not separated by time the later assignment will occur. A signal has a current value and a future value. Signal assignments are not updated until after the current simulation cycle. You've updated the future value before it could be assigned to the current value in the next simulation cycle with a clock C'event and C = '1'.
The following uses the numeric_std package instead of the Synopsys std_logic_unsigned package without changing the type of tmp, hence the type conversions to and from unsigned. I simply didn't want to divert my ieee library to contain something non-standard compliant. You can use std_logic_unsigned and remove the type conversions.
You could likewise declare signal tmp as unsigned (2 downto 0) and type convert it when assigning to Q (Q <= std_logic_vector(tmp);) or if possible make both Q and tmp unsigned.
library ieee;
use ieee.std_logic_1164.all;
--use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity newtest is
port(C, CLR : in std_logic;
Q : out std_logic_vector(2 downto 0));
end newtest;
architecture archi of newtest is
signal tmp: std_logic_vector(2 downto 0);
begin
process (C, CLR)
begin
if (CLR='1') then
tmp <= "000";
elsif (C'event and C='1') then
if (tmp="100") then
tmp <= std_logic_vector (unsigned (tmp) + 2);
else
tmp <= std_logic_vector (unsigned (tmp) + 1);
end if;
end if;
end process;
Q <= tmp;
end archi;
Now there is only ever one assignment to tmp and it should go from "100" to "110". Someone is bound to point out tmp could be an unsigned instead of a std_logic_vector, or tmp could be an integer instead of either.
As far as synthesized hardware adding increment by 2 requires an additional term input for the two rightmost bits of tmp input

Resources