-------------------------------------------------------------------------------
-- Title :
-- Project    : Arithmetic blocks
-------------------------------------------------------------------------------
-- File        : arit.VHD
-- Author      : Jamil Khatib  
-- Organization: OpenIPCore Project
-- Created     : 2000/04/12
-- Last update : 2000/04/17
-- Platform    : 
-- Simulators  : Modelsim 5.3XE / Windows98
-- Synthesizers: Leonardo / WindowsNT
-- Target      : 
-- Dependency  : 
-------------------------------------------------------------------------------
-- Description: Arithmetic blocks
-------------------------------------------------------------------------------
-- Copyright (c) 2000 Jamil Khatib
-- 
-- This VHDL design file is an open design; you can redistribute it and/or
-- modify it and/or implement it under the terms of the Openip General Public
-- License as it is going to be published by the OpenIPCore Organization and
-- any coming versions of this license.
-- You can check the draft license at
-- http://www.openip.org/oc/license.html

-------------------------------------------------------------------------------
-- Revisions  :
-- Revision Number :   1
-- Version         :   0.1
-- Date            :   12th Apr 2000
-- Modifier        :   Jamil Khatib (khatib@ieee.org)
-- Desccription    :   Created
--
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Revision Number :   2
-- Version         :   0.2
-- Date            :   17th Apr 2000
-- Modifier        :   Jamil Khatib (khatib@ieee.org)
-- Desccription    :   More generic
--
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity ScaleMAC is

  generic (
    OPSIZE : integer := 8);             -- Operand size


  port (
    Op1 : in  std_logic_vector(OPSIZE - 1 downto 0);  -- Operand 1
    Op2 : in  std_logic_vector(OPSIZE - 1 downto 0);  -- Operand 2
    Res : out std_logic_vector(OPSIZE -1 downto 0);   -- Result

    Overflow : out std_logic;           -- Overflow
    ValidOut : out std_logic;           -- valid output active high
    clk      : in  std_logic;           -- system clock positive edge
    rst_n    : in  std_logic);          -- system reset active low

end ScaleMAC;


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;


architecture behavior of ScaleMAC is

begin  -- behavior

  -- purpose: calculates MAC using serial approach
  -- type   : sequential
  -- inputs : clk    positive edge
  --          rst_n  active low
  -- outputs: 
  mac : process (clk, rst_n)

    function BitsToSpan(num : integer) return integer is
      variable work         : integer;
    begin
      work   := num-1;
      for i in 1 to 32 loop
        work := work/2;
        if (work = 0) then return i; end if;
      end loop;
--  report "BitsToSpan: Input too large" severity error;
      return 0;

    end;


    variable op2tmp   : std_logic_vector(OPSIZE - 1 downto 0);
                                        -- Temporary store of operand 2
    variable op1tmp   : std_logic_vector(OPSIZE - 1 downto 0);
                                        -- Temporary store of operand 1
    variable tmpres   : std_logic_vector(OPSIZE - 1 downto 0);
                                        -- Temporary result
    variable andres   : std_logic_vector(OPSIZE -1 downto 0);  -- Anding result
    variable count    : std_logic_vector(BitsToSpan(OPSIZE)-1 downto 0);  -- counter
    variable validvar : std_logic;      -- ValidOut variable





  begin  -- process mac

    if rst_n = '0' then                 -- asynchronous reset (active low)

      ValidOut <= '1';
      Res      <= (others => '0');
      validvar := '1';
      op2tmp   := (others => '0');
      op1tmp   := (others => '0');
      tmpres   := (others => '0');
      andres   := (others => '1');
      count    := (others => '0');
      Overflow <= '0';

    elsif clk'event and clk = '1' then  -- rising clock edge

      andres := (others => '1');

      if validvar = '1' then

        ValidOut <= '0';
        validvar := '0';
        tmpres   := (others => '0');
        op1tmp   := op1;
        op2tmp   := op2;

        Overflow <= '0';

      end if;


      if count = (count'range => '1') then


        ValidOut <= '1';
        validvar := '1';

        for i in 0 to OPSIZE -1 loop
          andres(i) := op1tmp(i) and op2tmp(OPSIZE - 1 - conv_integer(count));
        end loop;  -- i


        tmpres := andres + tmpres;
-- No shift in the last clock

        Res   <= tmpres;
        count := (others => '0');

      else


        for i in 0 to OPSIZE -1 loop
          andres(i) := op1tmp(i) and op2tmp(OPSIZE - 1 - conv_integer(count));
        end loop;  -- i

        tmpres := andres + tmpres;

        if tmpres(OPSIZE -1 ) = '1' then
          Overflow <= '1';
        end if;

        tmpres := tmpres(OPSIZE -2 downto 0 ) & '0';
        Res    <= tmpres;

      end if;


      count := count + 1;

    end if;
  end process mac;

end behavior;