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

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [divu32.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
--
83
 
84
library ieee;
85
  use ieee.std_logic_1164.all;
86
  use ieee.numeric_std.all;
87
  use ieee.std_logic_unsigned.all;
88
--library unisim;
89
--  use unisim.vcomponents.all;
90
 
91
entity udiv32 is
92
  port (
93
    --
94
    -- CPU Interface signals
95
    --
96
    clk      : in  std_logic;                     -- CPU Clock
97
    rst      : in  std_logic;                     -- Reset input (active high)
98
    cs       : in  std_logic;                     -- Chip Select
99
    addr     : in  std_logic_vector(3 downto 0);  -- Register Select
100
    rw       : in  std_logic;                     -- Read / Not Write
101
    data_in  : in  std_logic_vector(7 downto 0);  -- Data Bus In 
102
    data_out : out std_logic_vector(7 downto 0)  -- Data Bus Out
103
    );
104
end udiv32;
105
--================== End of entity ==============================--
106
 
107
-------------------------------------------------------------------
108
-- Architecture for unsigned 32 bit integer divider interface
109
-------------------------------------------------------------------
110
 
111
architecture rtl of udiv32 is
112
 
113
signal dividend      : std_logic_vector(31 downto 0) := (others => '0');
114
signal divisor       : std_logic_vector(31 downto 0) := (others => '0');
115
signal result        : std_logic_vector(31 downto 0) := (others => '0');
116
signal count         : std_logic_vector( 4 downto 0) := (others => '0');
117
signal start_flag    : std_logic := '0';
118
signal finish_flag   : std_logic := '0';
119
 
120
signal dividend_temp : std_logic_vector(64 downto 0);
121
signal divisor_temp  : std_logic_vector(64 downto 0);
122
 
123
begin
124
 
125
--
126
-- Write registers
127
--
128
udiv32_write : process( clk, rst, data_in, finish_flag )
129
begin
130
  if falling_edge( clk ) then
131
    if rst = '1' then
132
      dividend    <= (others=> '0');   -- reset the dividend to zero
133
      divisor     <= (others=> '0');   -- reset the divisor to zero
134
      start_flag  <= '0';                                        -- the default state is stopped
135
    else
136
      --
137
      -- start bit is normally reset
138
      --
139
      start_flag <= '0';
140
      --
141
      -- write to registers
142
      --
143
      if (cs = '1') and (rw = '0') then
144
        case addr is
145
        when "0000" =>
146
          dividend(31 downto 24) <= data_in;
147
        when "0001" =>
148
          dividend(23 downto 16) <= data_in;
149
        when "0010" =>
150
          dividend(15 downto  8) <= data_in;
151
        when "0011" =>
152
          dividend( 7 downto  0) <= data_in;
153
        when "0100" =>
154
          divisor(31 downto 24)  <= data_in;
155
        when "0101" =>
156
          divisor(23 downto 16)  <= data_in;
157
        when "0110" =>
158
          divisor(15 downto  8)  <= data_in;
159
        when "0111" =>
160
          divisor( 7 downto  0)  <= data_in;
161
          --
162
          -- writing the last byte of the divisor 
163
                         -- should pulse the start flag high for one cycle 
164
                         -- starting the division,
165
          -- provided the previous division has finished
166
          --
167
                         if (finish_flag = '1') then
168
                                start_flag <= '1';
169
                         end if;
170
        when others =>
171
           null;
172
        end case;
173
      end if;
174
    end if; -- rst
175
  end if; -- clk
176
end process;
177
 
178
--
179
-- Read registers
180
--
181
udiv32_read : process( addr, dividend, divisor, result, dividend_temp )
182
begin
183
  case addr is
184
  when "0000" =>
185
    data_out <= dividend(31 downto 24);
186
  when "0001" =>
187
    data_out <= dividend(23 downto 16);
188
  when "0010" =>
189
    data_out <= dividend(15 downto  8);
190
  when "0011" =>
191
    data_out <= dividend( 7 downto  0);
192
  when "0100" =>
193
    data_out <= divisor(31 downto 24);
194
  when "0101" =>
195
    data_out <= divisor(23 downto 16);
196
  when "0110" =>
197
    data_out <= divisor(15 downto  8);
198
  when "0111" =>
199
    data_out <= divisor( 7 downto  0);
200
  when "1000" =>
201
    data_out <= result(31 downto 24);
202
  when "1001" =>
203
    data_out <= result(23 downto 16);
204
  when "1010" =>
205
    data_out <= result(15 downto  8);
206
  when "1011" =>
207
    data_out <= result( 7 downto  0);
208
  when "1100" =>
209
    data_out <= dividend_temp(31 downto 24);
210
  when "1101" =>
211
    data_out <= dividend_temp(23 downto 16);
212
  when "1110" =>
213
    data_out <= dividend_temp(15 downto  8);
214
  when "1111" =>
215
    data_out <= dividend_temp( 7 downto  0);
216
  when others =>
217
    null;
218
  end case;
219
end process;
220
 
221
--
222
-- When the finish flag is high and the start flag goes high, 
223
-- start the division by clearing the finish flag
224
-- When the finish flag is low and the count reaches 31 
225
udiv32_divide : process( rst, clk, start_flag, finish_flag )
226
variable result_temp    : std_logic_vector(64 downto 0);
227
begin
228
  if falling_edge( clk ) then
229
    if (rst = '1') then
230
      dividend_temp  <= (others=>'0');
231
      divisor_temp   <= (others=>'0');
232
      result_temp    := (others=>'0');
233
      result         <= (others=>'0');
234
      count          <= (others=>'0');
235
      finish_flag    <= '1';             -- default state is finished
236
    else
237
      --
238
      -- start the division if the last division was complete
239
                -- i.e. the finish flag was set
240
      -- and the last byte of the divisor was just written
241
      -- i.e. the start flag was pulsed high for one clock cycle
242
                --
243
      if (start_flag = '1') and (finish_flag = '1') then
244
        dividend_temp(64)           <= '0';                    -- dividend carry bit
245
        dividend_temp(63 downto 32) <= (others => '0');        -- zero MSW
246
        dividend_temp(31 downto  0) <= dividend(31 downto 0);  -- Mantissa in the bottom
247
 
248
        divisor_temp(64)            <= '0';                    -- divisor carry bit
249
        divisor_temp(63)            <= '0';                    -- 
250
        divisor_temp(62 downto 31)  <= divisor(31 downto 0);   -- divisor starts off one bit down in MSW
251
        divisor_temp(30 downto  0)  <= (others => '0');        -- bottom of divisor is zero
252
 
253
        result_temp                 := (others => '0');        -- clear the result variable
254
 
255
        count                       <= (others => '0');        -- zero the bit counter
256
        finish_flag                 <= '0';                    -- flag that the division is in progress
257
 
258
      elsif ( finish_flag = '0' ) then                         -- if finish flag is clear the division must be in progress
259
 
260
        result_temp   := dividend_temp - divisor_temp;         -- subtract the divisor from the dividend
261
 
262
        if result_temp(64) = '0' then                          -- if the result carry is clear
263
          dividend_temp <= result_temp;                        -- update the dividend variable with the result variable
264
        end if;
265
        --
266
        -- shift divisor down one bit
267
        --
268
        divisor_temp(62 downto 0) <= divisor_temp(63 downto 1);
269
        --
270
        -- shift the result up one bit
271
        -- The LSBit is the inverted result carry
272
        --
273
        result(0)           <= not result_temp(64);
274
        result(31 downto 1) <= result(30 downto 0);
275
        --
276
        -- 32 bit division should take 32 clock cycles
277
        --
278
        count               <= count + "00001";
279
        --
280
                  -- When the count reaches the 31st cycle of the division 
281
        -- flag that the division is complete by setting the finish flag.
282
        -- 
283
        if count = "11111" then
284
          finish_flag <= '1';  -- flag division complete
285
        end if;
286
 
287
      end if; -- start/finish
288
    end if; -- rst
289
  end if; -- clk
290
end process;
291
 
292
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.