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

Subversion Repositories qfp32

[/] [qfp32/] [trunk/] [Units/] [norm.vhd] - Rev 2

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

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
 
library work;
use work.qfp_p.all;
 
package qfp32_norm_p is
 
  type raw_norm_t is record
    zero     : std_ulogic;
    err      : std_ulogic;
    mant     : unsigned(28 downto 0);
    exp      : unsigned(2 downto 0);
    rounding : std_ulogic;
  end record raw_norm_t;
 
  function normMant (
    raw : unsigned; -- raw mantissa (unnormalized mant + block*(steps-1)
    exp : unsigned;
    dont_shft : std_ulogic)
    return raw_norm_t;
 
end package qfp32_norm_p;
 
package body qfp32_norm_p is
 
  function normMant (
    raw : unsigned; -- raw format: ov (n-bits) | mant | shifted in m=(steps-1)*block bits
    exp : unsigned; -- exponent: min=0 max=2*k-2
    dont_shft : std_ulogic)
    return raw_norm_t is
 
    constant blockSize : natural := 8;
    constant numBlocks : natural := 4;
    constant mantSize : natural := 29;
    constant mantRestSize : natural := mantSize-((numBlocks-1)*blockSize);  -- 5                                                                      
 
    variable ov : std_ulogic;
    variable zero : std_ulogic_vector(numBlocks-2 downto 0);
    variable norm : unsigned(mantSize downto 0);
    variable slice : natural;
    variable shft : unsigned(log2(numBlocks)-1 downto 0);
    variable mant_zero : std_ulogic_vector(numBlocks-1 downto 0);
    variable full_mant_zero : std_ulogic;
  begin
 
    zero := (others => '0');
    -- check which blocks are zero
    for i in 0 to numBlocks-2 loop
      slice := raw'length-i*blockSize;
      if raw(slice-1 downto slice-blockSize) = to_unsigned(0,blockSize) then
        zero(i) := '1';
      end if;
    end loop;  -- i
 
    -- check if mant is zero
    -- mant depends on shft value but all top block must be zero
    -- select correct block from mant_zero by using shft    
    mant_zero := (others => '0');
    if zero = (numBlocks-2 downto 0 => '1') then
      for i in 0 to numBlocks-1 loop
        if raw(mantSize-1 downto mantSize-mantRestSize-8*i) = to_unsigned(0,mantRestSize+i*8) then
          mant_zero(i) := '1';
        end if;
      end loop;  -- i
    end if;
 
    -- calc shift
    shft := to_unsigned(0,log2(numBlocks));
    for i in 0 to numBlocks-2 loop
      if zero(i) = '0' or exp = i  then
        exit; -- break
      end if;
      shft := shft+1;
    end loop;  -- i
 
    -- check for format overflow
    ov := '0';
    if exp > numBlocks-1 then -- possible overflow
      for i in numBlocks to (numBlocks-1)*2 loop  
        if zero(i-numBlocks) = '0' and exp >= i then
          ov := '1';
        end if;
      end loop;  -- i      
    end if;
 
    -- make sure we dont shift if not allowed
    if dont_shft = '1' then
      shft := to_unsigned(0,shft'length);
      ov := to_ulogic(exp > blockSize-1);
    end if;
 
    norm := fast_shift(raw,to_integer(shft)*blockSize,fast_shift_left,'0')(raw'length-1 downto raw'length-mantSize-1);
 
    return (mant_zero(to_integer(shft)),ov,norm(mantSize downto 1),exp-shft,norm(0));
 
  end function;
 
end package body qfp32_norm_p;
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
 
library work;
use work.qfp_p.all;
use work.qfp32_norm_p.all;
 
entity qfp_norm is
 
  port (
    clk_i      : in  std_ulogic;
    reset_n_i  : in  std_ulogic;
 
    -- raw interface
    raw_i      : in  qfp32_raw_t;
 
    -- result
    result_o : out qfp32_t;
    result_zero_o : out std_ulogic);
 
end entity qfp_norm;
 
architecture Rtl of qfp_norm is
 
  signal is_ext : std_ulogic;
  signal err : std_ulogic;
  signal mant : unsigned(28 downto 0);
  signal full_mant : unsigned(33 downto 0);
  signal exp : unsigned(2 downto 0);
  signal rounding : std_ulogic;
  signal rd_mant : unsigned(34 downto 0);
  signal rounding_err : std_ulogic;
  --signal rd_add : unsigned(33 downto 0);
  signal zero : std_ulogic;
 
  signal norm : raw_norm_t;
 
begin  -- architecture Rtl
 
  process (err, exp, exp(1 downto 0), full_mant, full_mant(28 downto 0),
           full_mant(33 downto 8), is_ext, mant, raw_i.exp, raw_i.extMant,
           raw_i.ov, raw_i.sign, rd_mant(29), rounding_err, zero)
  begin  -- process
 
    is_ext <= '0';
    if raw_i.ov /= to_unsigned(0,5) then
      is_ext <= '1';
    end if;
 
    -- <<
    (zero,err,mant,exp,rounding) <= normMant(raw_i.extMant,raw_i.exp,is_ext);
 
    full_mant <= raw_i.ov & mant;
 
    -- round
    rd_mant <= '0' & full_mant;
    --if enableRounding and rounding = '1' then
    --  if is_ext = '0' then
    --    rd_add <= to_unsigned(1,34);
    --  else
    --    rd_add <= to_unsigned(256,34);
    --  end if;
 
    --  rd_mant <= fast_add(full_mant,rd_add,'0');
    --end if;
 
    rounding_err <= '0';
 
    -- check if fmt must be shifted right >>
    if rd_mant(29) = '1' or is_ext = '1' then-- overflow to next fmt cause of rounding
      if exp >= 3 then
        rounding_err <= '1';
      end if;      
    end if;
 
    -- if value is zero => sign must be 0
    result_o.fmt.sign <= raw_i.sign;
    if zero = '1' and is_ext = '0' then
      result_o.fmt.sign <= '0';
    end if;
 
    -- shift >> or select overflow
    result_o.fmt.exp <= to_unsigned(3,2);
    result_o.mant <= to_unsigned(2**29-1,29);  
    if rounding_err = '0' and err = '0' then
      if rd_mant(29) = '0' and is_ext = '0' then
        result_o.mant <= full_mant(28 downto 0);
        result_o.fmt.exp <= exp(1 downto 0);
      else
        result_o.mant <= "000" & full_mant(33 downto 8);
        result_o.fmt.exp <= exp(1 downto 0)+to_unsigned(1,2);
      end if;
    end if;
 
  end process;
 
  result_zero_o <= zero and not is_ext;
 
end architecture Rtl;
 

Go to most recent revision | 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.