--
-- Copyright (c) 1999-2000 University of California, Riverside.
-- Permission to copy is granted provided that this header remains
-- intact.  This software is provided with no warranties.
--
-- Version : 1.0
--

-------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;

-------------------------------------------------------------------------------

entity CCDPP is

    generic(STAT_REG_ADDR : INTEGER := 65531;
            CMND_REG_ADDR : INTEGER := 65532;
            DATA_REG_ADDR : INTEGER := 65533;
            IMAGE_WIDTH   : INTEGER := 16;
            IMAGE_HEIGHT  : INTEGER := 16);
  
    port(rst      : in  STD_LOGIC;
         clk      : in  STD_LOGIC;
         addr     : in  UNSIGNED (15 downto 0);
         in_data  : in  UNSIGNED (7 downto 0);
         out_data : out UNSIGNED (7 downto 0);
         rd       : in  STD_LOGIC;
         wr       : in  STD_LOGIC;
         ccd_rd   : out STD_LOGIC;
         ccd_data : in  UNSIGNED (7 downto 0));
end CCDPP;

-------------------------------------------------------------------------------

architecture BHV of CCDPP is

    type ROW_TYPE is array (0 to IMAGE_WIDTH-1) of UNSIGNED (7 downto 0);
    type IMAGE_TYPE is array (0 to IMAGE_HEIGHT-1) of ROW_TYPE;
    type STATE_TYPE is (ST_IDLE, ST_WAIT, ST_GETROW,
                        ST_GETBIAS, ST_FIXBIAS);

    constant CD_8 : UNSIGNED (7 downto 0) := "--------";
    constant CZ_8 : UNSIGNED (7 downto 0) := "ZZZZZZZZ";
    constant C0_8 : UNSIGNED (7 downto 0) := "00000000";
    constant C1_8 : UNSIGNED (7 downto 0) := "00000001";

    signal row   : INTEGER range 0 to IMAGE_HEIGHT;
    signal col   : INTEGER range 0 to IMAGE_WIDTH;
    signal busy  : STD_LOGIC;
    signal bias  : UNSIGNED (7 downto 0);
    signal image : IMAGE_TYPE;
    signal state : STATE_TYPE;
begin

    process(rst, clk)

        variable v8 : UNSIGNED (7 downto 0);
    begin
    
        if( rst = '1' ) then
      
            row <= 0;
            col <= 0;
            busy <= '0';
            bias <= CD_8;

            for i in 0 to IMAGE_HEIGHT-1 loop

                for j in 0 to IMAGE_WIDTH-1 loop

                    image(i)(j) <= CD_8;
                end loop;
            end loop;
          
            state <= ST_IDLE;
            out_data <= CZ_8;
            ccd_rd <= '0';
            
        elsif( clk'event and clk = '1' ) then

            out_data <= CZ_8;

            -- bus i/o
            if( wr = '1' and conv_integer(addr) = CMND_REG_ADDR ) then

                busy <= '1';
            end if;
            if( rd = '1' and conv_integer(addr) = STAT_REG_ADDR ) then

                out_data <= "0000000" & busy;
            end if;
            if( rd = '1' and conv_integer(addr) = DATA_REG_ADDR ) then

                out_data <= image(row)(col);
                col <= col + 1;
                if( col = IMAGE_WIDTH-1 ) then

                    row <= row + 1;
                    col <= 0;
                end if;
            end if;

            -- compute
            case state is
                when ST_IDLE =>
                    if( busy = '1' ) then

                        row <= 0;
                        col <= 0;
                        state <= ST_WAIT;
                        ccd_rd <= '1';
                    end if;

                when ST_WAIT =>
                    state <= ST_GETROW;
                    
                when ST_GETROW =>
                    if( row = IMAGE_HEIGHT ) then

                        row <= 0;
                        col <= 0;
                        busy <= '0';
                        state <= ST_IDLE;
                        ccd_rd <= '0';
                    elsif( col = IMAGE_WIDTH ) then

                        col <= 0;
                        bias <= ccd_data;
                        state <= ST_GETBIAS;
                    else
                      
                        image(row)(col) <= ccd_data;
                        col <= col + 1;
                    end if;
            
                when ST_GETBIAS =>
                    v8 := bias + ccd_data;
                    bias <= "0" & v8(7 downto 1);
                    state <= ST_FIXBIAS;
                    ccd_rd <= '0';

                when ST_FIXBIAS =>
                    if( col = IMAGE_WIDTH ) then

                        col <= 0;
                        row <= row + 1;
                        state <= ST_GETROW;
                        ccd_rd <= '1';
                    else

                        image(row)(col) <= image(row)(col) + bias;
                        col <= col + 1;
                    end if;
            end case;
        end if;
    end process;
end BHV;
