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

Subversion Repositories plasma_fpu

[/] [plasma_fpu/] [trunk/] [src/] [cores/] [div_core.vhd] - Rev 2

Compare with Previous | Blame | View Log

-- --------------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<<<<
-- --------------------------------------------------------------------------
-- TITLE:       Divider core
-- AUTHOR:      Steve Rhoads (rhoadss@yahoo.com)  
--              Alex Schoenberger (Alex.Schoenberger@ies.tu-darmstadt.de)
-- COMMENT:
--
-- www.ies.tu-darmstadt.de
-- TU Darmstadt
-- Institute for Integrated Systems
-- Merckstr. 25
-- 
-- 64283 Darmstadt - GERMANY
-- --------------------------------------------------------------------------
-- PROJECT:       Plasma CPU core with FPU
-- FILENAME:      mult_core.vhd
-- --------------------------------------------------------------------------
-- COPYRIGHT: 
--  This project is distributed by GPLv2.0
--  Software placed into the public domain by the author.
--  Software 'as is' without warranty.  Author liable for nothing.
-- --------------------------------------------------------------------------
-- DESCRIPTION:
--        long upper=a, lower=0;
--        a = b << 31;
--        for(i = 0; i < 32; ++i)
--        {
--          lower = lower << 1;
--          if(upper >= a && a && b < 2)
--          {
--            upper = upper - a;
--            lower |= 1;
--          }
--          a = ((b&2) << 30) | (a >> 1);
--          b = b >> 1;
--        }
--
--    SYNTHESIZABLE
--
----------------------------------------------------------------------------
-- Revision History
-- --------------------------------------------------------------------------
-- Revision   Date    Author     CHANGES
-- 1.0      7/2014    AS         initial
-- --------------------------------------------------------------------------
library IEEE;
  use IEEE.std_logic_1164.ALL;
  use IEEE.numeric_std.ALL;
 
entity div_core is
  port(
    clk               : in  std_logic;
    rst               : in  std_logic;
 
    start             : in  std_logic;
    busy              : out std_logic;
    rdy               : out std_logic;
 
    sign_flag         : in  std_logic;
 
    a                 : in  std_logic_vector(31 downto 0);
    b                 : in  std_logic_vector(31 downto 0);
 
    c                 : out std_logic_vector(31 downto 0);
    r                 : out std_logic_vector(31 downto 0)
  );
end entity div_core;
 
--           _____   _____ _    _ _____ _______ ______ _____ _______ _    _ _____  ______ 
--     /\   |  __ \ / ____| |  | |_   _|__   __|  ____/ ____|__   __| |  | |  __ \|  ____|
--    /  \  | |__) | |    | |__| | | |    | |  | |__ | |       | |  | |  | | |__) | |__   
--   / /\ \ |  _  /| |    |  __  | | |    | |  |  __|| |       | |  | |  | |  _  /|  __|  
--  / ____ \| | \ \| |____| |  | |_| |_   | |  | |___| |____   | |  | |__| | | \ \| |____ 
-- /_/    \_\_|  \_\\_____|_|  |_|_____|  |_|  |______\_____|  |_|   \____/|_|  \_\______|
architecture structure_div_core of div_core is
  -- _ _  _ ___  _  _ ___ 
  -- | |\ | |__] |  |  |  
  -- | | \| |    |__|  |  
  alias flag_a_neg              : std_logic is a(31);               -- operand A is negative
  alias flag_b_neg              : std_logic is b(31);               -- operand B is negative
 
  signal a_convert              : std_logic_vector(31 downto 0);    -- twoscomplement of operand A
  signal b_convert              : std_logic_vector(31 downto 0);    -- twoscomplement of operand B  
 
  signal a_input                : std_logic_vector(31 downto 0);
  signal b_input                : std_logic_vector(31 downto 0);
 
  -- ____ ____ ____ _ ____ ___ ____ ____ ____ 
  -- |__/ |___ | __ | [__   |  |___ |__/ [__  
  -- |  \ |___ |__] | ___]  |  |___ |  \ ___]
  signal i_rem, reg_rem         : std_logic_vector(31 downto 0);
  signal i_qot, reg_qot         : std_logic_vector(31 downto 0);
 
  signal reg_divisor            : std_logic_vector(31 downto 0);
 
  signal reg_sign_a             : std_logic;
  signal reg_xor_sign           : std_logic;
 
  -- ___  ____ ___ ____ ___  ____ ___ _  _ 
  -- |  \ |__|  |  |__| |__] |__|  |  |__| 
  -- |__/ |  |  |  |  | |    |  |  |  |  | 
  signal i_sub                  : std_logic_vector(32 downto 0);
  alias  flag_sub_neg           : std_logic is i_sub(32);
 
  -- ____ ____ _  _ ___ ____ ____ _    ___  ____ ___ _  _ 
  -- |    |  | |\ |  |  |__/ |  | |    |__] |__|  |  |__| 
  -- |___ |__| | \|  |  |  \ |__| |___ |    |  |  |  |  | 
  type t_div_state              is ( s_IDLE, s_INPUT, s_WORK );
 
  signal i_state, state         : t_div_state;
 
  type t_div_flags is
    record
      input_en                  : std_logic;
      work_en                   : std_logic;
      cnt_en                    : std_logic;
      cnt_done                  : std_logic;
    end record;
 
  signal flags                  : t_div_flags;                      -- internal flags
 
  -- ____ ____ _  _ _  _ ___ ____ ____ 
  -- |    |  | |  | |\ |  |  |___ |__/ 
  -- |___ |__| |__| | \|  |  |___ |  \   
  signal div_counter            : std_logic_vector(4 downto 0);     -- 2**5 = 32 clock cycles for division
 
  -- ____ _  _ ___ ___  _  _ ___ 
  -- |  | |  |  |  |__] |  |  |  
  -- |__| |__|  |  |    |__|  |  
  signal qot_convert            : std_logic_vector(31 downto 0);    -- twoscomplement of quotient
  signal rem_convert            : std_logic_vector(31 downto 0);    -- twoscomplement of remainder
 
begin
-- synthesis translate_off
  -- ____ ____ _  _ _ ___ _   _    ____ _  _ ____ ____ _  _ 
  -- [__  |__| |\ | |  |   \_/     |    |__| |___ |    |_/  
  -- ___] |  | | \| |  |    |      |___ |  | |___ |___ | \_ 
  sanity_process:process( a, b )
  begin
    assert (not((a = x"8000_0000") and (sign_flag = '1'))) report "WARNING: operand A of DIV-CORE is 0x8000_0000, result will be erroneous!" severity warning;
    assert (not((b = x"8000_0000") and (sign_flag = '1'))) report "WARNING: operand B of DIV-CORE is 0x8000_0000, result will be erroneous!" severity warning;
  end process;
-- synthesis translate_on
 
  -- _ _  _ ___  _  _ ___ 
  -- | |\ | |__] |  |  |  
  -- | | \| |    |__|  |  
  --
  -- calculate twoscomplement
  --
  a_convert <= std_logic_vector( unsigned(not a) + to_unsigned(1, 32) );
  b_convert <= std_logic_vector( unsigned(not b) + to_unsigned(1, 32) );
 
  --
  -- for signed multiplication and negative operand B take twoscomplements
  --
  a_input   <= a_convert when (flag_a_neg and sign_flag) = '1' else a;
  b_input   <= b_convert when (flag_b_neg and sign_flag) = '1' else b;
 
  -- ____ ____ ____ _ ____ ___ ____ ____ ____ 
  -- |__/ |___ | __ | [__   |  |___ |__/ [__  
  -- |  \ |___ |__] | ___]  |  |___ |  \ ___]
  --
  -- reg_qot : quotient register
  -- reg_rem : remainder register
  -- reg_divisor : divisor register
  --
  -- reg_sign_a : detect negative dividend -> remainder should have the same sign 
  -- reg_xor_sign : detect different signs of operands -> result should be negative
  --
  -- counter value and state variable
  --
  mul_registers:
  process( clk )
  begin
    if rising_edge( clk ) then
      if rst = '1' then                                   -- << RESET ACTIVE
        reg_qot         <= (others => '0');
        reg_rem         <= (others => '0');
        reg_divisor     <= (others => '0');
 
        reg_sign_a      <= '0';
        reg_xor_sign    <= '0';
 
        div_counter     <= (others => '0');
        state           <= s_IDLE;
      else                                                -- << RISING EDGE OF CLK
        -- ############ FIRST INPUT ################
        if flags.input_en = '1' then
 
          reg_qot       <= a_input;
          reg_rem       <= (others => '0');
          reg_divisor   <= b_input;
 
          reg_sign_a    <= flag_a_neg and sign_flag;
          reg_xor_sign  <= (flag_a_neg xor flag_b_neg) and sign_flag;
 
        else
          -- ########## CALCULATION ################
          if flags.work_en = '1' then
            reg_qot     <= i_qot;
            reg_rem     <= i_rem;
          end if;
        end if;
 
        if flags.cnt_en = '1' then
          div_counter <= std_logic_vector(unsigned(div_counter) + to_unsigned(1, 5));
        else
          div_counter <= (others => '0');
        end if;
 
        state         <= i_state;                       -- always active
      end if;
    end if;
  end process;
 
  -- ___  ____ ___ ____ ___  ____ ___ _  _ 
  -- |  \ |__|  |  |__| |__] |__|  |  |__| 
  -- |__/ |  |  |  |  | |    |  |  |  |  | 
 
  i_sub <= std_logic_vector(unsigned('0' & reg_rem(30 downto 0) & reg_qot(31))        -- '0' for sign and shift dividend
                            - 
                            unsigned('0' & reg_divisor));                             -- substract divisor
 
  i_qot <= reg_qot(30 downto 0) & (not i_sub(32));
  i_rem <= reg_rem(30 downto 0) & reg_qot(31) when i_sub(32) = '1' else i_sub(31 downto 0);
 
  -- ____ ____ _  _ ___ ____ ____ _    ___  ____ ___ _  _ 
  -- |    |  | |\ |  |  |__/ |  | |    |__] |__|  |  |__| 
  -- |___ |__| | \|  |  |  \ |__| |___ |    |  |  |  |  | 
  div_control:
  process( start, state, flags.cnt_done )
  begin
    -- ######## DEFAULT VALUES
    --
    -- intern flags
    --
    flags.input_en          <= '0';           -- no input
    flags.work_en           <= '0';           -- no calculation
    flags.cnt_en            <= '0';           -- no counting
 
    --
    -- state variable
    --
    i_state                 <= s_IDLE;        -- waiting for commands
 
    --
    -- outputs
    --
    busy                    <= '0';           -- no calculation indication
    rdy                     <= '0';           -- no result indication
 
    -- ######### CONTROL LOGIC
    case state is
      when s_IDLE   =>
 
        if start = '1' then
          busy              <= '1';
          flags.input_en    <= '1';
 
          i_state           <= s_INPUT;
        end if;
 
      when s_INPUT  =>                        -- write initial values
 
        busy                <= '1';
 
        flags.work_en       <= '1';           -- and start calculation
        flags.cnt_en        <= '1';
 
        i_state             <= s_WORK;
 
      when s_WORK   =>
 
        busy                <= '1';
 
        if flags.cnt_done = '1' then          -- finish calculation
          rdy               <= '1';
        else
          flags.work_en     <= '1';
          flags.cnt_en      <= '1';
 
          i_state           <= s_WORK;
        end if;
 
      when others   =>
    end case;
  end process;
 
  -- ____ ____ _  _ _  _ ___ ____ ____ 
  -- |    |  | |  | |\ |  |  |___ |__/ 
  -- |___ |__| |__| | \|  |  |___ |  \ 
  --
  -- get counter flag
  --
  flags.cnt_done  <= '1' when div_counter = "00000" else '0';
 
  -- ____ _  _ ___ ___  _  _ ___ 
  -- |  | |  |  |  |__] |  |  |  
  -- |__| |__|  |  |    |__|  |  
  --
  -- calculate twoscomplement of results
  --
  qot_convert     <= std_logic_vector(unsigned(not reg_qot) + to_unsigned(1, 32) );
  rem_convert     <= std_logic_vector(unsigned(not reg_rem) + to_unsigned(1, 32) );
 
  --
  -- result is negative for signed division and different signs of operands 
  -- remainder has the same sign as dividend
  --
  c               <= qot_convert when reg_xor_sign = '1' else reg_qot;
  r               <= rem_convert when reg_sign_a   = '1' else reg_rem;
 
 
end architecture structure_div_core;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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