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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [VHDL/] [threshold_comp.vhd] - Rev 323

Compare with Previous | Blame | View Log

-- Copyright (c)2022 Jeremy Seth Henry
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
--     * Redistributions of source code must retain the above copyright
--       notice, this list of conditions and the following disclaimer.
--     * 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,
--       where applicable (as part of a user interface, debugging port, etc.)
--
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``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 JEREMY SETH HENRY 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.
--
-- VHDL Units :  threshold_comp
-- Description:  Compares the value on Port_A to either Port_B or a fixed,
--            :   unsigned constant with hysteresis.
--
-- Revision History
-- Author          Date     Change
------------------ -------- ---------------------------------------------------
-- Seth Henry      06/29/22 Initial import
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
 
entity threshold_comp is
generic(
  Constant_B            : boolean := TRUE;
  Hysteresis            : integer := 2;
  Threshold             : integer := 0;
  Bus_Width             : integer := 16;
  Reset_Level           : std_logic := '1'
);
port(
  Clock                 : in  std_logic;
  Reset                 : in  std_logic;
  --
  Port_A_Data           : in  std_logic_vector(Bus_Width - 1 downto 0);
  Port_A_Update         : in  std_logic;
  Port_B_Data           : in  std_logic_vector(Bus_Width - 1 downto 0) := (others => '0');
  Port_B_Update         : in  std_logic := '0';
  --
  A_GT_B                : out std_logic;
  A_LTE_B               : out std_logic
);
end entity;
 
architecture behave of threshold_comp is
 
  function limit_int (x : in integer; y : in integer ) return integer is
    variable upper      : integer;
    variable retval     : integer;
  begin
    upper               := (2**y) - 1;
 
    if( x <= 0 )then
      retval            := 0;
    elsif( x > upper )then
      retval            := upper;
    else
      retval            := x;
    end if;
    return retval;
  end function;
 
  constant Int_Width    : integer := Bus_Width + 1;
 
  constant Comp_Val_r_i : integer := Threshold + Hysteresis;
  constant Comp_Val_r_l : integer := limit_int(Comp_Val_r_i, Int_Width);
  constant Comp_Val_r   : std_logic_vector(Bus_Width downto 0) :=
                            conv_std_logic_vector(Comp_Val_r_l, Int_Width);
 
  constant Comp_Val_f_i : integer := Threshold - Hysteresis;
  constant Comp_Val_f_l : integer := limit_int(Comp_Val_f_i, Int_Width);
  constant Comp_Val_f   : std_logic_vector(Bus_Width downto 0) :=
                            conv_std_logic_vector(Comp_Val_f_l, Int_Width);
 
  signal Hist_Dir       : std_logic := '0';
  signal Update_q       : std_logic := '0';
  signal Update_qq      : std_logic := '0';
 
  signal Port_A_q       : std_logic_vector(Bus_Width downto 0) :=
                            (others => '0');
 
  signal Port_B_r       : std_logic_vector(Bus_Width downto 0) :=
                            (others => '0');
 
  signal Port_B_f       : std_logic_vector(Bus_Width downto 0) :=
                            (others => '0');
 
  signal Port_A_LT_B    : std_logic := '0';
 
begin
 
Constant_Port_B : if( Constant_B )generate
 
  Compare_proc: process( Clock, Reset )
  begin
    if( Reset = Reset_Level )then
      Update_q          <= '0';
      Hist_Dir          <= '1';
      Port_A_q          <= (others => '0');
      A_GT_B            <= '0';
      A_LTE_B           <= '1';
    elsif( rising_edge(Clock) )then
 
      -- Update the internal registers on Update, then start a short shift
      --  register to pipeline the logic.
      Update_q          <= Port_A_Update;
      if( Port_A_Update = '1' )then
        Port_A_q        <= '0' & Port_A_Data;
      end if;
 
      -- Update the output on q
      if( Update_q = '1' )then
        if( Hist_Dir = '1' and Port_A_q >= Comp_Val_r )then
          Hist_Dir      <= '0';
          A_GT_B        <= '1';
          A_LTE_B       <= '0';
        end if;
        if( Hist_Dir = '0' and Port_A_q <= Comp_Val_f )then
          Hist_Dir      <= '1';
          A_GT_B        <= '0';
          A_LTE_B       <= '1';
        end if;
      end if;
 
    end if;
  end process;
 
end generate;
 
Variable_Port_B : if( not Constant_B )generate
 
  Compare_proc: process( Clock, Reset )
  begin
    if( Reset = Reset_Level )then
      Update_q          <= '0';
      Update_qq         <= '0';
      Hist_Dir          <= '1';
      Port_A_q          <= (others => '0');
      Port_B_r          <= (others => '0');
      Port_B_f          <= (others => '0');
      A_GT_B            <= '0';
      A_LTE_B           <= '1';
    elsif( rising_edge(Clock) )then
 
      -- Update the internal registers on Update, then start a short shift
      --  register to pipeline the logic.
      Update_q          <= Port_A_Update or Port_B_Update;
 
      if( Port_A_Update = '1' )then
        Port_A_q        <= '0' & Port_A_Data;
      end if;
 
      if( Port_B_Update = '1' )then
        Port_B_r        <= ('0' & Port_B_Data) + Hysteresis;
        Port_B_f        <= ('0' & Port_B_Data) - Hysteresis;
      end if;
 
      -- Clip the upper and lower thresholds so that the comparator can't get
      --  stuck and will trip on equal.
      Update_qq          <= Update_q;
 
      if( Port_B_R(Bus_Width) = '1' )then
        Port_B_R(Bus_Width) <= '0';
        Port_B_R(Bus_Width - 1 downto 0) <= (others => '1');
      end if;
 
      if( Port_B_F(Bus_Width) = '1' )then
        Port_B_F        <= (others => '0');
      end if;
 
      -- Update the output on qq to give the clipping logic a chance to update
      if( Update_qq = '1' )then
        if( Hist_Dir = '1' and Port_A_q >= Port_B_r )then
          Hist_Dir      <= '0';
          A_GT_B        <= '1';
          A_LTE_B       <= '0';
        end if;
        if( Hist_Dir = '0' and Port_A_q <= Port_B_f )then
          Hist_Dir      <= '1';
          A_GT_B        <= '0';
          A_LTE_B       <= '1';
        end if;
      end if;
 
    end if;
  end process;
 
end generate;
 
end architecture;

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.