VHDL modular multiplication always resulting 0 in simulation

I'm trying to implement a modular multiplication algorithm in VHDL, but the result "r" is set to 0 on every simulation. I would like to know how to fix it.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity mod_multiplier is
generic (
N : integer := 8;
P : signed := "100000001"
);

port (
clk, rst : in std_logic;
mult_a, mult_b : in signed(N downto 0);
r : out signed(N+1 downto 0)
);
end mod_multiplier;

architecture arch of mod_multiplier is
signal s, t : signed(N+1 downto 0);
begin

process(clk, rst)
begin
if rst = '1' then
s <= (others => '0');
t <= (others => '0');
elsif rising_edge(clk) then
for i in 0 to N loop
if (s(0) = '0') then
if (mult_a(i)='1') then
t <= s + ('0' & mult_b);
s <= '0' & t(N+1 downto 1);
else
t <= s;
s <= '0' & t(N+1 downto 1);
end if;
else
if (mult_a(i)='1') then
t <= s + ('0' & mult_b) + ('0' & P);
s <= '0' & t(N+1 downto 1);
else
t <= s + P;
s <= '0' & t(N+1 downto 1);
end if;
end if;
end loop;

if s >=('0' & P) then
t <= s;
s <= t - ('0'&P);
else
s <= s;
end if;

end if;
r <= s;
end process;

end arch;

• your code is quite messy ... it needs to be formatted properly for easier reading Nov 29, 2023 at 0:39
• Processes suspend and resume in wait statements, here the implicit one as a final statement with the sensitivity list defined for the process. Signals update earlier in a simulation cycle than processes execute. Updates are scheduled in a projected output waveform queue which can have only one value for any time calculated from the current simulation time plus the time in the waveform after clause (which defaults 0). The last value written in the loop statement will be the one scheduled. s and t could be variables instead. There's no guarantee all those N operations can occur in one clock. Nov 29, 2023 at 7:25
• @user16145658 Please make this an actual answer, comments are not for this. Nov 29, 2023 at 7:27
• @user16145658 Thanks. This woul be far more useful as an answer. Nov 30, 2023 at 12:20

The user user16145658 posted the following comment:

Processes suspend and resume in wait statements, here the implicit one as a final statement with the sensitivity list defined for the process. Signals update earlier in a simulation cycle than processes execute. Updates are scheduled in a projected output waveform queue which can have only one value for any time calculated from the current simulation time plus the time in the waveform after clause (which defaults 0). The last value written in the loop statement will be the one scheduled. s and t could be variables instead. There's no guarantee all those N operations can occur in one clock. – user16145658

For the little I know about this language, this seems helpful. I am going to offer help that may work in combination with this advice, since I am a Senior Developer with more than 15 years of professional software development experience.

First, get smaller parts of your code working. I get the impression that you typed all of this in, and you're just expecting all of it to work. I've been there myself... and had the same results.

So... break it up into smaller pieces, and test each piece. Then slowly integrate -- get two working pieces to work together, then another two, and so on. Code is best built like Tetris -- no gaps, out of simple pieces, ever building a solid foundation.

Also, another way... Get working the simplest thing that could possibly work. Then build on that, step by step.

As you improve your mental model, you may suddenly have an epiphany, and suddenly understand what's wrong with your previous code, and just reach in and fix it. True understanding is precious, and crucial for your forward progress.

Code is also like Sudoku -- it's impossible to fix errors because you don't know what's lying to you, you no longer have a firm foundation upon which to build well, and the cost of fixing it exponentially grows so much that the only real solution is to start over. This is reflected in the agile development methodology short development cycles which do better than waterfall methodology, improving the growing foundation by ensuring correctness as they continue to grow. The book Code Complete says that "Quality is free" and it pays you to do it right the first time, because every error is exponentially bad.

Another advice that I have is an interesting angle for this. Including an interactive microcontroller core, like a Forth core, in your FPGA allows you to put in some small primitives and then "probe" them interactively to see what the behavior is. There exists a family of Forth cores popular with EE's called the J1 family, which includes both VHDL and SystemVerilog cores. This amounts to including a resident monitor in the FPGA itself, which can be used to interactively probe your generated fabric from the inside, to see how it really behaves. And you can add your own growing set of FPGA analysis/development tools to the Forth cores, which will speed up the whole process.

If you're interested in pursuing this avenue, there is a non-J1-derivative SystemVerilog Forth core by a Facebook group called AI and Robotics, of which I am a member. The leader of the group, Don Golding, has regularly done presentations on progress at the Silicon Valley Forth Interest Group which I also regularly attend. We use this board, having the great Lattice UltraPlus ICE40UP5K FPGA with 5.3K LUTs, 1Mb SPRAM, 120Kb DPRAM, and 8 Multipliers. There have been some excellent presentations by Christopher Lozinski, a PhD student developing some Forth boards as part of his degree, especially his talk on the Review of Soft Core Forth Processors -- Christopher Lozinski -- 2023-08-26.

There is also a J1-derivative VHDL Forth core at OpenCores called the H2 Forth SoC, which looks pretty good. Just reading its VHDL code might be interesting, or give you some ideas.

You will find that the Forth cores are the smallest of FPGA cpu cores that exist, as that has been their mission from the beginning. Both small and simple (comparatively). This, and its famous interactive development ability, may be why they continue to be used on NASA missions and satellites.

And if you don't know Forth, the outstanding pico-ice RP2040 plus Lattice iCE40UP5K FPGA (for \$35-USD as of Dec. 5, 2023) has the same FPGA our "AI and Robotics" group uses, but also a Raspberry Pi processor as well, which means that you can get a similarly interactive MicroPython REPL running on the RP2040 Pi chip and probe the FPGA from the outside, which is probably not nearly as good as being in the same fabric.

Full disclosure: I have nothing to profit from the sale of any of these boards. But we may need some people in our group who love to whip up FPGA boards, so feel free to join our "AI and Robotics" group.

• I love the comparison with Tetris, it is completely new to me after all these years. Dec 3, 2023 at 10:53
• Thank you very much for your very insightful answer, to be honest i may have asked my question a little too early in the process of correcting it,since this multiplier is part of a project that involves implementations that haven't been documented well(i for now haven't found any previous VHDL implementation of it) i decided to ask it way too fast,right now i managed to get better results by correcting my code i am going to modify my question or delete this one and ask another that includes my new code that isn't actually giving perfect results yet ( i am really stuck this time for a while now Dec 3, 2023 at 18:54
• @Anis_bsh -- Better not to delete your question. Even if it is no longer helpful to you, it, and this answer, may be helpful to those who are searching. Dec 4, 2023 at 5:15