OpenCores
URL https://opencores.org/ocsvn/System09/System09/trunk

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [divu32_s2.vhd] - Blame information for rev 138

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 130 dilbert57
--===========================================================================--
2
--                                                                           --
3
--                  Synthesizable unsigned 32 bit integer divider            --
4
--                                                                           --
5
--===========================================================================--
6
--
7
--  File name      : divu32.vhd
8
--
9
--  Entity name    : udiv32
10
--
11
--  Purpose        : Implements a 32 bit unsigned integer divider 
12
--                  
13
--  Dependencies   : ieee.std_logic_1164
14
--                   ieee.numeric_std
15
--                   ieee.std_logic_unsigned
16
--
17
--  Author         : John E. Kent
18
--
19
--  Email          : dilbert57@opencores.org      
20
--
21
--  Web            : http://opencores.org/project,system09
22
--
23
--  Registers      :
24
--  0 Dividend  1st Byte MSB
25
--  1           2nd Byte
26
--  2           3rd Byte 
27
--  3           4th Byte LSB
28
--  4 Divisor   1st Byte MSB
29
--  5           2nd Byte
30
--  6           3rd Byte
31
--  7           4th Byte LSB
32
--  8 Result    1st Byte MSB
33
--  9           2nd Byte
34
-- 10           3rd Byte
35
-- 11           4th byte LSB
36
-- 12 Remainder 1st Byte MSB
37
-- 13           2nd Byte
38
-- 14           3rd Byte
39
-- 15           4th byte LSB
40
--
41
--  32 bit unsigned binary division.
42
--
43
--  Write the most significant byte of the dividend at the 0th register first 
44
--  down to the least significant byte of the divisor in the 7th register.
45
--  Writing the least significant byte of the divisor will start the division.
46
--
47
--  The 32 bit division will take 32 clock cycles.
48
--  There is no status register so the CPU must execute a software delay
49
--  to wait 32 clock cycles after the least significant byte of the divisor 
50
--  is written before reading the result of the division or the remainder.
51
--
52
--  The dividend and divisor input registers are read/writable
53
--  The result and remainder output registers are read only.
54
--  The result register holds the integer part of the result of the division.
55
--  The remainder register holds the dividend modulo the divisor.
56
--
57
--  Copyright (C) 2012 - 2014 John Kent
58
--
59
--  This program is free software: you can redistribute it and/or modify
60
--  it under the terms of the GNU General Public License as published by
61
--  the Free Software Foundation, either version 3 of the License, or
62
--  (at your option) any later version.
63
--
64
--  This program is distributed in the hope that it will be useful,
65
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
66
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
67
--  GNU General Public License for more details.
68
--
69
--  You should have received a copy of the GNU General Public License
70
--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
71
--
72
--===========================================================================--
73
--                                                                           --
74
--                              Revision  History                            --
75
--                                                                           --
76
--===========================================================================--
77
--
78
-- Version Author        Date         Changes
79
--
80
-- 0.1     John Kent     2012-04-06    Initial version
81
-- 0.2     John Kent     2014-05-07    Replaced Status register with 4 byte remainder
82
-- 0.3     John Kent     2016-02-04    Shortend result_temp to 33 bits so subtraction is faster.
83
--                                     Add hold output to pause CPU until result is valid.
84
 
85
library ieee;
86
  use ieee.std_logic_1164.all;
87
  use ieee.numeric_std.all;
88
  use ieee.std_logic_unsigned.all;
89
--library unisim;
90
--  use unisim.vcomponents.all;
91
 
92
entity udiv32 is
93
  port (
94
    --
95
    -- CPU Interface signals
96
    --
97
    clk      : in  std_logic;                     -- CPU Clock
98
    rst      : in  std_logic;                     -- Reset input (active high)
99
    cs       : in  std_logic;                     -- Chip Select
100
    addr     : in  std_logic_vector(3 downto 0);  -- Register Select
101
    rw       : in  std_logic;                     -- Read / Not Write
102
    data_in  : in  std_logic_vector(7 downto 0);  -- Data Bus In 
103
    data_out : out std_logic_vector(7 downto 0);  -- Data Bus Out
104
         hold     : out std_logic                      -- Result access hold
105
    );
106
end udiv32;
107
--================== End of entity ==============================--
108
 
109
-------------------------------------------------------------------
110
-- Architecture for unsigned 32 bit integer divider interface
111
-------------------------------------------------------------------
112
 
113
architecture rtl of udiv32 is
114
 
115
signal dividend      : std_logic_vector(31 downto 0) := (others => '0');
116
signal divisor       : std_logic_vector(31 downto 0) := (others => '0');
117
signal result        : std_logic_vector(31 downto 0) := (others => '0');
118
signal remainder     : std_logic_vector(63 downto 0) := (others => '0');
119
signal count         : std_logic_vector( 4 downto 0) := (others => '0');
120
signal req_flag      : std_logic := '0';  -- Request Division
121
signal act_flag      : std_logic := '0';  -- Division Active
122
 
123
begin
124
 
125
--
126
-- Write registers
127
--
128
udiv32_write : process( clk, rst, cs, rw, addr, data_in, act_flag, req_flag )
129
begin
130
  if rst = '1' then
131
      dividend    <= (others=> '0');   -- reset the dividend to zero
132
      divisor     <= (others=> '0');   -- reset the divisor to zero
133
      req_flag    <= '0';                                   -- the default state is stopped
134
  elsif falling_edge( clk ) then
135
      --
136
      -- write to registers
137
      --
138
      if (cs = '1') and (rw = '0') then
139
        case addr is
140
        when "0000" =>
141
          dividend(31 downto 24) <= data_in;
142
        when "0001" =>
143
          dividend(23 downto 16) <= data_in;
144
        when "0010" =>
145
          dividend(15 downto  8) <= data_in;
146
        when "0011" =>
147
          dividend( 7 downto  0) <= data_in;
148
        when "0100" =>
149
          divisor(31 downto 24)  <= data_in;
150
        when "0101" =>
151
          divisor(23 downto 16)  <= data_in;
152
        when "0110" =>
153
          divisor(15 downto  8)  <= data_in;
154
        when "0111" =>
155
          divisor( 7 downto  0)  <= data_in;
156
          --
157
          -- writing the last byte of the divisor 
158
                         -- should pulse the request flag high for one cycle 
159
                         -- starting the division,
160
          -- provided the previous division has finished
161
          --
162
                         if (act_flag = '0') and (req_flag = '0') then
163
                                req_flag <= '1';
164
                         end if;
165
        when others =>
166
           null;
167
        end case;
168
      end if;
169
  end if; -- rst/clk
170
  if( act_flag = '1') and (req_flag = '1') then
171
    req_flag <= '0';
172
  end if;
173
  hold <= cs and rw and addr(3) and act_flag;
174
end process;
175
 
176
--
177
-- Read registers
178
--
179
udiv32_read : process( addr, dividend, divisor, result, remainder )
180
begin
181
  case addr is
182
  when "0000" =>
183
    data_out <= dividend(31 downto 24);
184
  when "0001" =>
185
    data_out <= dividend(23 downto 16);
186
  when "0010" =>
187
    data_out <= dividend(15 downto  8);
188
  when "0011" =>
189
    data_out <= dividend( 7 downto  0);
190
  when "0100" =>
191
    data_out <= divisor(31 downto 24);
192
  when "0101" =>
193
    data_out <= divisor(23 downto 16);
194
  when "0110" =>
195
    data_out <= divisor(15 downto  8);
196
  when "0111" =>
197
    data_out <= divisor( 7 downto  0);
198
  when "1000" =>
199
    data_out <= result(31 downto 24);
200
  when "1001" =>
201
    data_out <= result(23 downto 16);
202
  when "1010" =>
203
    data_out <= result(15 downto  8);
204
  when "1011" =>
205
    data_out <= result( 7 downto  0);
206
  when "1100" =>
207
    data_out <= remainder(63 downto 56);
208
  when "1101" =>
209
    data_out <= remainder(55 downto 48);
210
  when "1110" =>
211
    data_out <= remainder(47 downto 40);
212
  when "1111" =>
213
    data_out <= remainder(39 downto 32);
214
  when others =>
215
    null;
216
  end case;
217
end process;
218
 
219
--
220
-- When the finish flag is high and the start flag goes high, 
221
-- start the division by clearing the finish flag
222
-- When the finish flag is low and the count reaches 31 
223
udiv32_divide : process( rst, clk, req_flag, act_flag )
224
variable remainder_temp    : std_logic_vector(32 downto 0);
225
begin
226
    if (rst = '1') then
227
      remainder      <= (others=>'0');
228
      remainder_temp := (others=>'0');
229
      result         <= (others=>'0');
230
      count          <= (others=>'0');
231
      act_flag       <= '0';             -- default state is inactive
232
    elsif falling_edge( clk ) then
233
      --
234
      -- activate the division if the last division was complete
235
                -- i.e. the active flag was clear
236
      -- and the last byte of the divisor was just written
237
      -- i.e. the request flag was pulsed high for one clock cycle
238
                --
239
      if (req_flag = '1') and (act_flag = '0') then
240
        remainder(63 downto 32) <= (others => '0');            -- Clear Most Significant Word of remainder
241
        remainder(31 downto  0) <= dividend(31 downto 0);      -- Dividend in the Least Significant Word of remainder
242
        remainder_temp          := (others => '0');            -- Clear the remainder temp variable
243
        count                   <= (others => '0');            -- Clear the bit counter
244
        act_flag                <= '1';                        -- Flag division in progress
245
 
246
      elsif (req_flag = '0') and (act_flag = '1') then                              -- If active flag is set the division must be in progress
247
 
248
        remainder_temp := (remainder(63 downto 31)) - ("0" & divisor);   -- subtract the divisor from the remainder
249
 
250
        if remainder_temp(32) = '0' then                           -- if the remainder temp carry is clear
251
          remainder(63 downto 32) <= remainder_temp(31 downto 0);  -- update the remainder variable with remainder temp
252
        else
253
          remainder(63 downto 32) <= remainder(62 downto 31);      -- shift remainder up one bit
254
                  end if;
255
        remainder(31 downto  1) <= remainder(30 downto 0);         -- shift remainder up one bit
256
                  remainder(0) <= '0';
257
 
258
        --
259
        -- shift the result up one bit
260
        -- The LSBit is the inverted remainder carry
261
        --
262
        result(31 downto 1) <= result(30 downto 0);
263
        result(0)           <= not remainder_temp(32);
264
        --
265
        -- 32 bit division should take 32 clock cycles
266
        --
267
        count               <= count + "00001";
268
        --
269
                  -- When the count reaches the 31st cycle of the division 
270
        -- flag that the division is complete by clrearing the active flag.
271
        -- 
272
        if count = "11111" then
273
          act_flag <= '0';  -- flag division complete
274
        end if;
275
 
276
      end if; -- start/finish
277
    end if; -- rst/clk
278
end process;
279
 
280
end rtl; -- end of architecture

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.