ci_div.vhd 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. -- altera vhdl_input_version vhdl_2008
  2. library ieee;
  3. use ieee.std_logic_1164.all;
  4. use ieee.numeric_std.all;
  5. library lpm;
  6. use lpm.lpm_components.all;
  7. use work.fifo_pkg.all;
  8. entity ci_div is
  9. port (
  10. clk : in std_logic;
  11. clk_en : in std_logic;
  12. reset : in std_logic;
  13. dataa : in std_logic_vector(31 downto 0);
  14. datab : in std_logic_vector(31 downto 0);
  15. result : out std_logic_vector(31 downto 0);
  16. start : in std_logic;
  17. done : out std_logic;
  18. n : in std_logic_vector(0 downto 0)
  19. );
  20. end entity;
  21. architecture arch of ci_div is
  22. constant CAPACITY : integer := 64;
  23. constant SHORT_ZERO : std_logic_vector(15 downto 0) := (others => '0');
  24. constant LONG_ZERO : std_logic_vector(47 downto 0) := (others => '0');
  25. component lpm_div
  26. port (
  27. clken : in std_logic;
  28. clock : in std_logic;
  29. denom : in std_logic_vector(31 downto 0);
  30. numer : in std_logic_vector(47 downto 0);
  31. quotient : out std_logic_vector(47 downto 0);
  32. remain : out std_logic_vector(31 downto 0)
  33. );
  34. end component;
  35. signal reg_shift_request : std_logic_vector(47 downto 0) := LONG_ZERO;
  36. signal reg_next_shift_request : std_logic_vector(47 downto 0);
  37. signal enqueue : std_logic := '0';
  38. signal dequeue : std_logic := '0';
  39. signal reg_queued : integer range 0 to CAPACITY := 0;
  40. signal reg_next_queued : integer range 0 to CAPACITY := 0;
  41. signal capacity_available : std_logic := '0';
  42. signal reg_dequeue_pending : std_logic := '0';
  43. signal reg_next_dequeue_pending : std_logic := '0';
  44. signal reg_enqueue_pending : std_logic := '0';
  45. signal reg_next_enqueue_pending : std_logic := '0';
  46. signal lpm_div_done : std_logic := '0';
  47. signal div_read : std_logic := '0';
  48. signal div_write : std_logic := '0';
  49. signal fifo_in : fifo_in_t := FIFO_IN_NOP;
  50. signal fifo_out : fifo_out_t;
  51. type lpm_in_t is
  52. record
  53. denom : std_logic_vector(31 downto 0);
  54. numer : std_logic_vector(47 downto 0);
  55. end record;
  56. constant LPM_IN_NOP : lpm_in_t := (ZERO, LONG_ZERO);
  57. type lpm_out_t is
  58. record
  59. quotient : std_logic_vector(47 downto 0);
  60. remain : std_logic_vector(31 downto 0);
  61. end record;
  62. signal lpm_in : lpm_in_t := LPM_IN_NOP;
  63. signal lpm_out : lpm_out_t;
  64. begin
  65. alt_fwft_fifo_inst : entity work.alt_fwft_fifo
  66. generic map (
  67. DATA_WIDTH => 32,
  68. NUM_ELEMENTS => CAPACITY
  69. )
  70. port map (
  71. aclr => reset,
  72. clock => clk,
  73. data => fifo_in.data,
  74. rdreq => fifo_in.rdreq,
  75. wrreq => fifo_in.wrreq,
  76. empty => fifo_out.empty,
  77. full => fifo_out.full,
  78. q => fifo_out.q
  79. );
  80. lpm_div_inst : component lpm_div
  81. port map (
  82. clken => clk_en,
  83. clock => clk,
  84. numer => lpm_in.numer,
  85. denom => lpm_in.denom,
  86. quotient => lpm_out.quotient,
  87. remain => lpm_out.remain
  88. );
  89. result <= fifo_out.q;
  90. enqueue <= (not n(0)) and start;
  91. dequeue <= n(0) and start;
  92. done <= div_read or div_write;
  93. capacity_available <= '1' when reg_queued < CAPACITY else '0';
  94. lpm_div_done <= reg_shift_request(47);
  95. div_read <= (dequeue or reg_dequeue_pending) and not fifo_out.empty;
  96. div_write <= (enqueue or reg_enqueue_pending) and capacity_available;
  97. fifo_in.wrreq <= lpm_div_done;
  98. fifo_in.data <= lpm_out.quotient(31 downto 0);
  99. fifo_in.rdreq <= div_read;
  100. sync : process(clk, clk_en, reset)
  101. begin
  102. if reset = '1' then
  103. -- reset values
  104. reg_shift_request <= LONG_ZERO;
  105. reg_enqueue_pending <= '0';
  106. reg_dequeue_pending <= '0';
  107. reg_queued <= 0;
  108. elsif clk_en = '1' and rising_edge(clk) then
  109. -- register transfer
  110. reg_shift_request <= reg_next_shift_request;
  111. reg_enqueue_pending <= reg_next_enqueue_pending;
  112. reg_dequeue_pending <= reg_next_dequeue_pending;
  113. reg_queued <= reg_next_queued;
  114. end if;
  115. end process;
  116. async : process(all)
  117. begin
  118. -- implement shift register for enqueue operations (to know when lpm_div is done)
  119. reg_next_shift_request(0) <= div_write;
  120. reg_next_shift_request(reg_shift_request'high downto 1) <= reg_shift_request(reg_shift_request'high - 1 downto 0);
  121. -- keep track of started enqueue operation if necessary
  122. if reg_enqueue_pending = '1' then
  123. -- deassert reg_enqueue_pending only once done is asserted
  124. reg_next_enqueue_pending <= not done;
  125. else
  126. reg_next_enqueue_pending <= enqueue and not capacity_available;
  127. end if;
  128. -- keep track of started dequeue operation if necessary
  129. if reg_dequeue_pending = '1' then
  130. -- deassert reg_dequeue_pending only once done is asserted
  131. reg_next_dequeue_pending <= not done;
  132. else
  133. reg_next_dequeue_pending <= dequeue and fifo_out.empty;
  134. end if;
  135. -- keep track of available capacity
  136. reg_next_queued <= reg_queued;
  137. if reg_queued > 0 and div_read = '1' then
  138. reg_next_queued <= reg_queued - 1;
  139. elsif reg_queued < CAPACITY and div_write = '1' then
  140. reg_next_queued <= reg_queued + 1;
  141. end if;
  142. -- extend dataa by 16 bits
  143. lpm_in.numer <= dataa & SHORT_ZERO;
  144. lpm_in.denom <= datab;
  145. end process;
  146. end architecture;