Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

modulo program in vhdl

Status
Not open for further replies.

clavin

Newbie level 4
Joined
Nov 12, 2011
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,319
i am making a vhdl code for finding remainder
i know there is a mod operator but still i am making the following program
the problem is suppose i divide 4 by 3 so in this case i have to subtract 4 by 3 only once so the program shows the necessary output
but lets say a loop is needed (for which i am trying to use the state) in that case the answer is not coming
i want to execute the code without for, while, etc loops but using states
so pls if possible do not suggest loops


Code:
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    20:14:25 11/10/2011 
-- Design Name: 
-- Module Name:    divi - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity divide is
  Port ( clk : in  STD_LOGIC;
         reset : in  STD_LOGIC;
			done: out std_logic;
         d : in  std_logic_vector(6 downto 0);
         c : in STD_LOGIC_vector(6 downto 0);

         remainder : out integer range 0 to 127);
end divide;

architecture Behavioral of divide is

type state_type is (s0);
signal current_s,next_s: state_type;


begin


process (clk,reset)

      begin
	
      if (reset='1') then
      current_s <= s0;
      elsif (rising_edge (clk)) then
      current_s <= next_s;
      end if;
end process;
process (current_s , c,d)

variable int1 : integer range 0 to 127;
variable int2 : integer range 0 to 127;

      begin
		
		int1 := conv_integer(c);
  int2 := conv_integer(d);
  
  
  
case current_s is

when s0=>


		remainder <= 0;
      done<='0';
		
		int1:=int1-int2;
		
		
		if(int1 < int2) then
		remainder <= int1;
		done<='1';
		 
		else
		next_s <= s0;
		end if;
		 

end case;
		
end process;

end Behavioral;
 

process (current_s , c,d) means that it will start whenever there is a change in the value of the current_s , c or d.

But within the process the value of current_s remains same as s0. You want process to run in loop in until "int1 < int2".
And since there is no change in the value of the current_s , c or d, the loop runs only once.

You can correct it in many ways. If we think in the same way as you have thought then in that case create 2 states s1 and s0 doing the exact same things
and just switching between one another.


process (current_s , c,d)

variable int1 : integer range 0 to 127;
variable int2 : integer range 0 to 127;

begin

int1 := conv_integer(c);
int2 := conv_integer(d);



case current_s is

when s0=>


remainder <= 0;
done<='0';

int1:=int1-int2;


if(int1 < int2) then
remainder <= int1;
done<='1';

else
next_s <= s1;
end if;

when s1=>


remainder <= 0;
done<='0';

int1:=int1-int2;


if(int1 < int2) then
remainder <= int1;
done<='1';

else
next_s <= s0;
end if;

end case;

end process;
 

there are better methods. you method scales with O(n) -- 15%1 will take 15 cycles to compute. however, using 3rd grade mathmatics, this can be improved to O(lg(n)). Yes, long division can be used. eg 15%4 is:
(0100000 > 1111) = 0
(0010000 > 1111) = 0
(0001000 < 1111) = 1
(0000100 < 0111) = 1
div = 0011. rem = 0011
4 cycles to get both results

Another serial modulo algorithm operates on a new lsb on each cycle. eg, if (tmp*2+lsb) >= modulus, then subtract modulus. This can also give division outputs with slight modifications. It also has similar complexity to long division. It relies on an understanding that if x is divisible by m, then 2x is also divisible by m.

even lower latency algorithms exist.

for both, I suggest states of: idle, processing, done. where idle waits for input values and a "go" signal. processing runs for a few cycles (you can use a counter to count the number of cycles). done holds the results and sets a "done" output signal. (cannot name the output "done" if the state is named "done" as that would be a name conflict).
 

@kunalvyas155
Well i tried that but still it didnt work for no where state change is required
it worked for 3 and 4 but not 3 and 8

@permute - well can u provide a lil vhdl snippet of what you are saying cuz as you can see i am having problem with the rapid changes of states here

#edit
ok this time i tried 3 and 7 so a total of 2 cycles needed using kunal's code
no state is repeated twice. even then the output wont come. i guess the jump to next state isnt working
i guess the problem is somewhere with clock because when i open the testbench and use the step command it shows its stopped here

-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1'; ---this line
 
Last edited:

firstly, no. there isn't any need to change state each cycle. I suggest starting with the state machine first. There should be 1 input, and 1 output. there should be 3 states. Internal to the design should be a counter.

when in the IDLE state, wait for "go" = '1', transition to the WORKING state.
when in the WORKING state, wait for count = N (eg, 10 for a 10b input), then transition to the DONE state.
when in the DONE state, transition to the IDLE state.

the counter should be set to 1 when not in the WORKING state, and should be count + 1 when in the working state.
Now this state machine will wait for "go", then run for N cycles, then 1 additional cycle (the output should be '1' during this cycle).

once you get that to work, you can modify the WORKING state, add additional logic, etc... to perform the actual task.
 

ok i found out the problem with my program now i only some one can help me to debug it
the problem is each time the state changes
these two statements are excuted again
int1 := conv_integer(c);
int2 := conv_integer(d);
and reset their values
so is their a way i can set int1 and int2 ouside of begin
 

I agree with permute, that there are better ways to design a sequential divider. Nevertheless, you should be able to make your original idea of repeated substraction work, otherwise it's unlikely that have better luck with other methods.

Following a state machine approach involves, that you define the purpose of each state in a reasonable way. You're now observing a problem of int1 and int2 being reloaded to their initial values in each clock cycle. Of course they do, that's how you commanded in your code.

A reasonable state machine would load int1 in an initial state, int2 is needed as a signal respectively variable only, if the input is expected to change after the initial state. I would personally suggest, to use a signal instead of a variable for int1 (and int2, if necessary), to follow a clear sequential design template.

Substraction should be performed in a second state, repeated as often as necessary.

To allow usage the sequential division unit in a real design, it should have a start input and done output.
 

ok thnx fvm
i got that working .
that having separate state for assignement was helpful
but as u guys told yea it is a lengthy process
so i did what permute said but now again the output comes 0
heres the code for long division


Code:
entity long is
  Port ( clk : in  STD_LOGIC;
         reset : in  STD_LOGIC;
			done: out std_logic;
         d : in  std_logic_vector(5 downto 0);
         c : in std_logic_vector(5 downto 0);

         remainder : out std_logic_vector(5 downto 0));
end long;

architecture Behavioral of long is

type state_type is (s0,s1,s2);
signal current_s: state_type;
signal next_s: state_type;

signal int1:std_logic_vector(5 downto 0);
signal int2:std_logic_vector(5 downto 0);
signal result:std_logic_vector(5 downto 0);

begin




process (Clk, reset,c,d,current_s)


 
BEGIN


IF Clk'EVENT AND Clk='1' THEN
 

 




case current_s is
 
when s0=>
int1<=c;
int2<=d;

result<="000000";
current_s<=s1;
when s1=>
if(int1>"000000") then
result<=result(4 downto 0) & '0';
if(int1<=int2) then
int2<=int2-int1;
result<=result+1;
end if;
int1<='0' & int1(5 downto 1);
else
remainder<=int1;
current_s<=s2;

end if;
when s2=>
done<='1';

end case;
 end if;
end process; 
end Behavioral;
 

well ok i got everything working
also did the long divison algorithm
now my true aim was to make lcm calculator
so i did everythin but this line is not working
int3<=int3+int3;
where int3 is std logic vector signal (5 downto 0)
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top