-- 
-- Operator.vhd 
--
-- Copyright (c) 2006 Mitsutaka Okazaki (brezza@pokipoki.org)
-- All rights reserved.
-- 
-- Redistribution and use of this source code or any derivative works, are 
-- permitted provided that the following conditions are met:
--
-- 1. Redistributions of source code must retain the above copyright notice, 
--    this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright 
--    notice, this list of conditions and the following disclaimer in the 
--    documentation and/or other materials provided with the distribution.
-- 3. Redistributions may not be sold, nor may they be used in a commercial 
--    product or activity without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
-- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
-- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
-- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
-- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
-- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use WORK.VM2413.ALL;

entity Operator is
  port (
    clk    : in std_logic;
    reset  : in std_logic;
    clkena : in std_logic;
    
    slot   : in SLOT_TYPE;    
    stage  : in STAGE_TYPE;
    rhythm : in std_logic;
        
    WF     : in WF_TYPE;
    FB     : in FB_TYPE;
       
    noise  : in std_logic;
    pgout  : in PGOUT_TYPE;
    egout  : in DB_TYPE;
    
    faddr  : out CH_TYPE;
    fdata  : in SIGNED_LI_TYPE;
    
    opout  : out SIGNED_DB_TYPE
  );        
end Operator;

architecture RTL of Operator is

  component AttackTable port (
    clk  : in std_logic;
    addr : in  DB_TYPE;
    data : out DB_TYPE  
  );
  end component;

  component SineTable port (
    clk     : in std_logic;
    wf      : in std_logic;
    addr    : in integer range 0 to (2 ** (PGOUT_TYPE'high+1) - 1);
    data    : out SIGNED_DB_TYPE
  );
  end component;
  
  signal addr : integer range 0 to (2 ** (PGOUT_TYPE'high+1) - 1);
  signal data : SIGNED_DB_TYPE;
  
begin

  SINTBL : SineTable port map ( clk, WF, addr, data );

  process(clk, reset)

    variable modula : std_logic_vector(LI_TYPE'high + 2 downto 0);
    variable opout_buf : SIGNED_DB_TYPE;
  
  begin
  
    if reset='1' then

      opout <= ( sign=>'0', value=>(others=>'0') );

    elsif clk'event and clk='1' then if clkena = '1' then
      
      if stage = 0 then      
      
        -- periodic noise
        if rhythm = '1' and ( slot = 14 or slot = 17 ) then -- HH or CYM
               
          if noise = '1' then
            addr <= 127; -- phase of max value
          else
            addr <= 383; -- phase of min value
          end if;
           
        elsif rhythm = '1' and slot = 15 then -- SD
               
          if pgout(pgout'high) = '1' then
            addr <= 127; -- phase of max value
          else
            addr <= 383; -- phase of min value
          end if;       
          
        elsif rhythm = '1' and slot = 16 then -- TOM       
          
          addr <= CONV_INTEGER(pgout);
          
        else 
        
          if slot mod 2 = 0 then
            if FB = "000" then            
              modula := (others => '0') ;              
            else      
              modula := "0" & fdata.value & "0";
              modula := SHR( modula, "111" - FB );               
            end if;            
          else
            modula := fdata.value & "00";         
          end if;
          
          if fdata.sign = '0' then          
            addr <= CONV_INTEGER(pgout + modula(pgout'range));
          else          
            addr <= CONV_INTEGER(pgout - modula(pgout'range));
          end if;
          
        end if;
        
      elsif stage = 1 then
      
        -- Wait for sine and attack table.
      
      elsif stage = 2 then
      
        -- output 
        if ( ( '0'&egout ) + ('0'&data.value) ) < "10000000" then
          opout_buf := ( sign=>data.sign, value=> egout + data.value ); 
        else
          opout_buf := ( sign=>data.sign, value=> (others=>'1') );
        end if;          
      
        -- read feedback data for the next slot
        if slot mod 2 = 1 then
          if slot/2 = 8 then 
            faddr <= 0;
          else
            faddr <= slot/2 + 1;
          end if;
        else
          faddr <= slot/2;
        end if;
        
        opout <= opout_buf;
      
      elsif stage = 3 then
      
        -- wait for feedback data.
      
      end if;

    end if; end if;     

  end process;

end RTL;
