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

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [divs32_s2.vhd] - Blame information for rev 130

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      : divs32.vhd
8
--
9
--  Entity name    : sdiv32
10
--
11
--  Purpose        : Implements a 32 bit signed 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 quotient    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 quotient of the division or the remainder.
51
--
52
--  The dividend and divisor input registers are read/writable
53
--  The quotient and remainder output registers are read only.
54
--  The quotient 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
-- 0.4     John Kent     2018-03-21    Changed unsigned udiv32 to signed sdiv32
85
--
86
library ieee;
87
  use ieee.std_logic_1164.all;
88
  use ieee.numeric_std.all;
89
  use ieee.std_logic_unsigned.all;
90
--library unisim;
91
--  use unisim.vcomponents.all;
92
 
93
entity sdiv32 is
94
  port (
95
    --
96
    -- CPU Interface signals
97
    --
98
    clk      : in  std_logic;                     -- CPU Clock
99
    rst      : in  std_logic;                     -- Reset input (active high)
100
    cs       : in  std_logic;                     -- Chip Select
101
    addr     : in  std_logic_vector(3 downto 0);  -- Register Select
102
    rw       : in  std_logic;                     -- Read / Not Write
103
    data_in  : in  std_logic_vector(7 downto 0);  -- Data Bus In 
104
    data_out : out std_logic_vector(7 downto 0);  -- Data Bus Out
105
         hold     : out std_logic                      -- Result access hold
106
    );
107
end sdiv32;
108
--================== End of entity ==============================--
109
 
110
-------------------------------------------------------------------
111
-- Architecture for unsigned 32 bit integer divider interface
112
-------------------------------------------------------------------
113
 
114
architecture rtl of sdiv32 is
115
 
116
signal dividend      : std_logic_vector(31 downto 0) := (others => '0');
117
signal divisor       : std_logic_vector(31 downto 0) := (others => '0');
118
signal result        : std_logic_vector(63 downto 0) := (others => '0');
119
signal quotient      : std_logic_vector(31 downto 0) := (others => '0');
120
signal remainder     : std_logic_vector(31 downto 0) := (others => '0');
121
signal count         : std_logic_vector( 4 downto 0) := (others => '0');
122
signal req_flag      : std_logic := '0';  -- Request Division
123
signal act_flag      : std_logic := '0';  -- Division Active
124
 
125
begin
126
 
127
--
128
-- Write registers
129
--
130
sdiv32_write : process( clk, rst, cs, rw, addr, data_in, req_flag, act_flag )
131
begin
132
  if rst = '1' then
133
      dividend    <= (others=> '0');   -- reset the dividend to zero
134
      divisor     <= (others=> '0');   -- reset the divisor to zero
135
      req_flag    <= '0';                                   -- the default state is stopped
136
  elsif falling_edge( clk ) then
137
      --
138
      -- write to registers
139
      --
140
      if (cs = '1') and (rw = '0') then
141
        case addr is
142
        when "0000" =>
143
          dividend(31 downto 24) <= data_in;
144
        when "0001" =>
145
          dividend(23 downto 16) <= data_in;
146
        when "0010" =>
147
          dividend(15 downto  8) <= data_in;
148
        when "0011" =>
149
          dividend( 7 downto  0) <= data_in;
150
        when "0100" =>
151
          divisor(31 downto 24)  <= data_in;
152
        when "0101" =>
153
          divisor(23 downto 16)  <= data_in;
154
        when "0110" =>
155
          divisor(15 downto  8)  <= data_in;
156
        when "0111" =>
157
          divisor( 7 downto  0)  <= data_in;
158
          --
159
          -- writing the last byte of the divisor 
160
                         -- should pulse the request flag high for one cycle 
161
                         -- starting the division,
162
          -- provided the previous division has finished
163
          --
164
                         if (req_flag = '0') and (act_flag = '0') then
165
                                req_flag <= '1';
166
                         end if;
167
        when others =>
168
           null;
169
        end case;
170
      end if;
171
  end if; -- rst/clk
172
  if (req_flag = '1') and (act_flag = '1') then
173
    req_flag <= '0';
174
  end if;
175
  hold <= cs and rw and addr(3) and act_flag;
176
end process;
177
 
178
--
179
-- Read registers
180
--
181
sdiv32_read : process( addr, dividend, divisor, quotient, remainder )
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 <= quotient(31 downto 24);
202
  when "1001" =>
203
    data_out <= quotient(23 downto 16);
204
  when "1010" =>
205
    data_out <= quotient(15 downto  8);
206
  when "1011" =>
207
    data_out <= quotient( 7 downto  0);
208
  when "1100" =>
209
    data_out <= remainder(31 downto 24);
210
  when "1101" =>
211
    data_out <= remainder(23 downto 16);
212
  when "1110" =>
213
    data_out <= remainder(15 downto 8);
214
  when "1111" =>
215
    data_out <= remainder(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
sdiv32_divide : process( rst, clk, dividend, divisor, remainder, req_flag, act_flag, count )
226
variable result_temp  : std_logic_vector(32 downto 0);
227
begin
228
    if (rst = '1') then
229
           result          <= (others=>'0');
230
                result_temp     := (others=>'0');
231
      remainder       <= (others=>'0');
232
      quotient        <= (others=>'0');
233
      count           <= (others=>'0');
234
      act_flag        <= '0';             -- default state is inactive
235
    elsif falling_edge( clk ) then
236
      --
237
      -- activate the division if the last division was complete
238
                -- i.e. the active flag was clear
239
      -- and the last byte of the divisor was just written
240
      -- i.e. the request flag was pulsed high for one clock cycle
241
                --
242
      if (req_flag = '1') and (act_flag = '0') then
243
                  --
244
                  -- put dividend in result and make positive
245
                  --
246
        result(63 downto 32) <= (others => '0');
247
                  if dividend(31) = '0' then
248
          result(31 downto  0) <= dividend;                 -- Dividend in the Least Significant Word of remainder
249
                  else
250
                    result(31 downto  0) <= "00000000000000000000000000000000" - dividend;
251
                  end if;
252
                  --
253
                  -- Initialize temp variables
254
                  --
255
        result_temp        := (others => '0');            -- Clear the remainder temp variable
256
                  --
257
                  -- reset bit counter and activate division
258
                  --
259
        count              <= (others => '0');            -- Clear the bit counter
260
        act_flag           <= '1';                        -- Flag division in progress
261
 
262
      elsif (req_flag = '0') and (act_flag = '1') then                              -- If active flag is set the division must be in progress
263
                  --
264
                  -- if dividend positive, subrtact divisor
265
                  -- if dividend negative, add divisor
266
                  --
267
        if (divisor(31)) = '0' then
268
          result_temp := result(63 downto 31) - (divisor(31) & divisor);   -- subtract the divisor from the remainder if positive
269
        else
270
          result_temp := result(63 downto 31) + (divisor(31) & divisor);   -- add the divisor to the remainder if negative
271
        end if;
272
 
273
                  --
274
                  -- if carry clear from add or subract
275
                  -- update the remainder
276
                  --
277
        if result_temp(32) = '0' then                          -- if the remainder temp carry is clear
278
          result(63 downto 32) <= result_temp(31 downto 0);    -- update the result with remainder
279
        else
280
          result(63 downto 32) <= result(62 downto 31);        -- otherwise shift remainder up one bit
281
                  end if;
282
 
283
        --
284
        -- shift the quotient up one bit
285
        -- The LSBit is the inverted remainder carry
286
        --
287
        result(31 downto  1) <= result(30 downto 0);        -- shift lower remainder up one bit
288
                  result(0) <= not result_temp(32);                   -- shift quotient in bottom of remainder
289
 
290
        --
291
        -- 32 bit division should take 32 clock cycles
292
        --
293
        count               <= count + "00001";
294
        --
295
                  -- When the count reaches the 31st cycle of the division 
296
        -- flag that the division is complete by clrearing the active flag.
297
        -- 
298
        if count = "11111" then
299
          act_flag <= '0';  -- flag division complete
300
        end if;
301
 
302
      end if; -- start/finish
303
 
304
                --
305
                -- negating the result will take another clock cycle.
306
                -- If the cpu is held on a read access of the
307
                -- quotient or remainder it may get the wrong result.
308
                --
309
 
310
                --
311
                -- quotient has sign of dividend exclusive or divisor
312
                --
313
      if( (dividend(31) xor divisor(31)) = '0') then
314
        quotient <= result(31 downto 0);
315
      else
316
        quotient <= "00000000000000000000000000000000" - result(31 downto 0);
317
      end if;
318
 
319
                --
320
                -- remainder has sign of dividend
321
                --
322
                if dividend(31) = '0' then
323
                  remainder <= result(63 downto 32);
324
                else
325
                  remainder <= "00000000000000000000000000000000" - result(63 downto 32);
326
                end if;
327
 
328
    end if; -- rst/clk
329
end process;
330
 
331
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.