--
--  text12.vhd
--    Imprementation of Text Mode 1,2.
--
--  Copyright (C) 2006 Kunihiko Ohnaka
--  All rights reserved.
--                                     http://www.ohnaka.jp/ese-vdp/
--
--  本ソフトウェアおよび本ソフトウェアに基づいて作成された派生物は、以下の条件を
--  満たす場合に限り、再頒布および使用が許可されます。
--
--  1.ソースコード形式で再頒布する場合、上記の著作権表示、本条件一覧、および下記
--    免責条項をそのままの形で保持すること。
--  2.バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の
--    著作権表示、本条件一覧、および下記免責条項を含めること。
--  3.書面による事前の許可なしに、本ソフトウェアを販売、および商業的な製品や活動
--    に使用しないこと。
--
--  本ソフトウェアは、著作権者によって「現状のまま」提供されています。著作権者は、
--  特定目的への適合性の保証、商品性の保証、またそれに限定されない、いかなる明示
--  的もしくは暗黙な保証責任も負いません。著作権者は、事由のいかんを問わず、損害
--  発生の原因いかんを問わず、かつ責任の根拠が契約であるか厳格責任であるか（過失
--  その他の）不法行為であるかを問わず、仮にそのような損害が発生する可能性を知ら
--  されていたとしても、本ソフトウェアの使用によって発生した（代替品または代用サ
--  ービスの調達、使用の喪失、データの喪失、利益の喪失、業務の中断も含め、またそ
--  れに限定されない）直接損害、間接損害、偶発的な損害、特別損害、懲罰的損害、ま
--  たは結果損害について、一切責任を負わないものとします。
--
--  Note that above Japanese version license is the formal document.
--  The following translation is only for reference.
--
--  Redistribution and use of this software 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.
--
-------------------------------------------------------------------------------
-- Contributors
--
--   Alex Wulms
--     - Improvement of the TEXT2 mode such as 'blink function'.
--
-------------------------------------------------------------------------------
-- Memo
--   Japanese comment lines are starts with "JP:".
--   JP: 日本語のコメント行は JP:を頭に付ける事にする
--
-------------------------------------------------------------------------------
-- Revision History
--
-- 29th,October,2006 modified by Kunihiko Ohnaka
--   - Insert the license text.
--   - Add the document part below.
--
-- 12nd,August,2006 created by Kunihiko Ohnaka
-- JP: VDPのコアの実装とスクリーンモードの実装を分離した
--
-------------------------------------------------------------------------------
-- Document
--
-- JP: TEXTモード1,2のメイン処理回路です。
--

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE WORK.VDP_PACKAGE.ALL;

ENTITY TEXT12 IS
  PORT(
    -- VDP CLOCK ... 21.477MHZ
    CLK21M  : IN STD_LOGIC;
    RESET   : IN STD_LOGIC;

    DOTSTATE : IN STD_LOGIC_VECTOR(1 DOWNTO 0);
    DOTCOUNTERX : IN STD_LOGIC_VECTOR(8 DOWNTO 0);
    DOTCOUNTERY : IN STD_LOGIC_VECTOR(8 DOWNTO 0);

    VDPMODETEXT1: IN STD_LOGIC;
    VDPMODETEXT2: IN STD_LOGIC;

    -- REGISTERS
    VDPR7FRAMECOLOR : IN STD_LOGIC_VECTOR( 7 DOWNTO 0);
    VDPR12BLINKCOLOR : IN STD_LOGIC_VECTOR( 7 DOWNTO 0);
    VDPR13BLINKPERIOD : IN STD_LOGIC_VECTOR( 7 DOWNTO 0);

    VDPR2PTNNAMETBLBASEADDR : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
    VDPR4PTNGENETBLBASEADDR : IN STD_LOGIC_VECTOR(5 DOWNTO 0);
    VDPR10R3COLORTBLBASEADDR : IN STD_LOGIC_VECTOR(10 DOWNTO 0);
    --
    PRAMDAT : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    PRAMADR : OUT STD_LOGIC_VECTOR(16 DOWNTO 0);
    TXVRAMREADEN : OUT STD_LOGIC;

    PCOLORCODE : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
    );
END TEXT12;
ARCHITECTURE RTL OF TEXT12 IS
  SIGNAL ITXVRAMREADEN : STD_LOGIC;
  SIGNAL ITXVRAMREADEN2 : STD_LOGIC;
  SIGNAL DOTCOUNTER24 : STD_LOGIC_VECTOR(4 DOWNTO 0);
  SIGNAL TXWINDOWX : STD_LOGIC;
  SIGNAL TXPREWINDOWX : STD_LOGIC;

  SIGNAL LOGICALVRAMADDRNAM : STD_LOGIC_VECTOR(16 DOWNTO 0);
  SIGNAL LOGICALVRAMADDRGEN : STD_LOGIC_VECTOR(16 DOWNTO 0);
  SIGNAL LOGICALVRAMADDRCOL : STD_LOGIC_VECTOR(16 DOWNTO 0);

  SIGNAL TXCHARCOUNTER  : STD_LOGIC_VECTOR(11 DOWNTO 0);
  SIGNAL TXCHARCOUNTERX : STD_LOGIC_VECTOR(6 DOWNTO 0);
  SIGNAL TXCHARCOUNTERSTARTOFLINE : STD_LOGIC_VECTOR(11 DOWNTO 0);

  SIGNAL PATTERNNUM : STD_LOGIC_VECTOR( 7 DOWNTO 0);
  SIGNAL PREPATTERN : STD_LOGIC_VECTOR( 7 DOWNTO 0);
  SIGNAL PREBLINK : STD_LOGIC_VECTOR( 7 DOWNTO 0);
  SIGNAL PATTERN : STD_LOGIC_VECTOR( 7 DOWNTO 0);
  SIGNAL BLINK : STD_LOGIC_VECTOR( 7 DOWNTO 0);
  SIGNAL TXCOLORCODE : STD_LOGIC;       -- ONLY 2 COLORS
  SIGNAL TXCOLOR : STD_LOGIC_VECTOR( 7 DOWNTO 0);

  -- FOR BLINK
  SIGNAL BLINKFRAMECOUNT :STD_LOGIC_VECTOR( 3 DOWNTO 0);
  SIGNAL BLINKSTATE : STD_LOGIC;
  SIGNAL BLINKPERIODCOUNT : STD_LOGIC_VECTOR( 3 DOWNTO 0);
BEGIN

  -- JP: RAMは DOTSTATEが"10","00"の試にアォレスひ衆して"01"でアクセスすに。
  -- JP: EIGHTDOTSTATEで見にと、
  -- JP:  0-1    READ PATTERN NUM.
  -- JP:  1-2    READ PATTERN
  -- JP: となに。
  --

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

  TXCHARCOUNTER <= TXCHARCOUNTERSTARTOFLINE + TXCHARCOUNTERX;
  -- JP: 界エリアのVRAMマィゴング
  LOGICALVRAMADDRNAM <=  (VDPR2PTNNAMETBLBASEADDR & TXCHARCOUNTER(9 DOWNTO 0)) WHEN VDPMODETEXT1 = '1' ELSE
                         (VDPR2PTNNAMETBLBASEADDR(6 DOWNTO 2) & TXCHARCOUNTER);

  LOGICALVRAMADDRGEN <=  VDPR4PTNGENETBLBASEADDR & PATTERNNUM & DOTCOUNTERY(2 DOWNTO 0);

  LOGICALVRAMADDRCOL <=  VDPR10R3COLORTBLBASEADDR(10 DOWNTO 3) & TXCHARCOUNTER(11 DOWNTO 3);

  TXVRAMREADEN <= ITXVRAMREADEN WHEN VDPMODETEXT1 = '1' ELSE
                  ITXVRAMREADEN OR ITXVRAMREADEN2 WHEN VDPMODETEXT2 = '1' ELSE
                  '0';
  --
  TXCOLOR <= VDPR12BLINKCOLOR WHEN (VDPMODETEXT2 = '1') AND (BLINKSTATE = '1') AND (BLINK(7) = '1') ELSE
             VDPR7FRAMECOLOR;
  PCOLORCODE <= TXCOLOR(7 DOWNTO 4) WHEN (TXWINDOWX = '1') AND (TXCOLORCODE = '1') ELSE
                TXCOLOR(3 DOWNTO 0) WHEN (TXWINDOWX = '1') AND (TXCOLORCODE = '0') ELSE
                VDPR7FRAMECOLOR(3 DOWNTO 0);

  --
  --
  PROCESS( CLK21M, RESET )
    VARIABLE BLINKFRAMECOUNTISMAX : STD_LOGIC;
  BEGIN
    IF(RESET = '1' ) THEN
      TXCHARCOUNTERX <= (OTHERS => '0');
      TXCHARCOUNTERSTARTOFLINE <= (OTHERS => '0');
      PATTERNNUM <= (OTHERS => '0');
      PATTERN <= (OTHERS => '0');
      PREPATTERN <= (OTHERS => '0');
      PREBLINK <= (OTHERS => '0');
      TXWINDOWX <= '0';
      TXPREWINDOWX <= '0';
      PRAMADR <= (OTHERS => '0');
      ITXVRAMREADEN <= '0';
      ITXVRAMREADEN2 <= '0';
      BLINKFRAMECOUNT <= (OTHERS => '0');
      DOTCOUNTER24 <= (OTHERS => '0');
    ELSIF (CLK21M'EVENT AND CLK21M = '1') THEN

      -- TIMING GENERATION
      CASE DOTSTATE IS
        WHEN "10" =>
          IF( DOTCOUNTERX = 12 ) THEN
            -- JP: DOTCOUNTERは"10"のタイミングでは館にカウンエアィシしていにので注意
            TXPREWINDOWX <= '1';
            DOTCOUNTER24 <= (OTHERS => '0');
          ELSE
            IF( DOTCOUNTERX = 240+12 ) THEN
              TXPREWINDOWX <= '0';
            END IF;
            -- THE DOTCOUNTER24(2 DOWNTO 0) COUNTS UP 0 TO 5,
            -- AND THE DOTCOUNTER24(4 DOWNTO 3) COUNTS UP 0 TO 3.
            IF( DOTCOUNTER24(2 DOWNTO 0) = "101" ) THEN
              DOTCOUNTER24(4 DOWNTO 3) <= DOTCOUNTER24(4 DOWNTO 3) + 1;
              DOTCOUNTER24(2 DOWNTO 0) <= "000";
            ELSE
              DOTCOUNTER24(2 DOWNTO 0) <= DOTCOUNTER24(2 DOWNTO 0) + 1;
            END IF;
          END IF;
        WHEN "00" =>
          NULL;
        WHEN "01" =>
          IF( DOTCOUNTERX = 16 ) THEN
            TXWINDOWX <= '1';
          ELSIF( DOTCOUNTERX = 240+16) THEN
            TXWINDOWX <= '0';
          END IF;
        WHEN "11" =>
          NULL;
        WHEN OTHERS => NULL;
      END CASE;


      CASE DOTSTATE IS
        WHEN "11" =>
          IF( TXPREWINDOWX = '1' ) THEN
            -- VRAM READ ADDRESS OUTPUT.
            CASE DOTCOUNTER24(2 DOWNTO 0) IS
              WHEN "000" =>
                IF( DOTCOUNTER24(4 DOWNTO 3) = "00" ) THEN
                  -- READ COLOR TABLE(TEXT2 BLINK)
                  -- IT IS USED ONLY ONE TIME PER 8 CHARACTERS.
                  PRAMADR <= LOGICALVRAMADDRCOL;
                  ITXVRAMREADEN2 <= '1';
                END IF;
              WHEN "001" =>
                -- READ PATTERN NAME TABLE
                PRAMADR <= LOGICALVRAMADDRNAM;
                ITXVRAMREADEN <= '1';
                TXCHARCOUNTERX <= TXCHARCOUNTERX + 1;
              WHEN "010" =>
                -- READ PATTERN GENERATOR TABLE
                PRAMADR <= LOGICALVRAMADDRGEN;
                ITXVRAMREADEN <= '1';
              WHEN "100" =>
                -- READ PATTERN NAME TABLE
                -- IT IS USED IF VDPMODE IS TEST2.
                PRAMADR <= LOGICALVRAMADDRNAM;
                ITXVRAMREADEN2 <= '1';
                IF( VDPMODETEXT2 = '1' ) THEN
                  TXCHARCOUNTERX <= TXCHARCOUNTERX + 1;
                END IF;
              WHEN "101" =>
                -- READ PATTERN GENERATOR TABLE
                -- IT IS USED IF VDPMODE IS TEST2.
                PRAMADR <= LOGICALVRAMADDRGEN;
                ITXVRAMREADEN2 <= '1';
              WHEN OTHERS =>
                NULL;
            END CASE;
          END IF;
        WHEN "10" =>
          ITXVRAMREADEN <= '0';
          ITXVRAMREADEN2 <= '0';
        WHEN "00" =>
          IF( DOTCOUNTERX = 11) THEN
            TXCHARCOUNTERX <= (OTHERS => '0');
            IF( DOTCOUNTERY = 0 )  THEN
              TXCHARCOUNTERSTARTOFLINE <= (OTHERS => '0');
            END IF;
          ELSIF( (DOTCOUNTERX = 240+11) AND (DOTCOUNTERY(2 DOWNTO 0) = "111") ) THEN
              TXCHARCOUNTERSTARTOFLINE <= TXCHARCOUNTERSTARTOFLINE + TXCHARCOUNTERX;
          END IF;
        WHEN "01" =>
          CASE DOTCOUNTER24(2 DOWNTO 0) IS
            WHEN "001" =>
              -- READ COLOR TABLE(TEXT2 BLINK)
              -- IT IS USED ONLY ONE TIME PER 8 CHARACTERS.
              IF( DOTCOUNTER24(4 DOWNTO 3) = "00" ) THEN
                PREBLINK <= PRAMDAT;
              END IF;
            WHEN "010" =>
              -- READ PATTERN NAME TABLE
              PATTERNNUM <= PRAMDAT;
            WHEN "011" =>
              -- READ PATTERN GENERATOR TABLE
              PREPATTERN <= PRAMDAT;
            WHEN "101" =>
              -- READ PATTERN NAME TABLE
              -- IT IS USED IF VDPMODE IS TEST2.
              PATTERNNUM <= PRAMDAT;
            WHEN "000" =>
              -- READ PATTERN GENERATOR TABLE
              -- IT IS USED IF VDPMODE IS TEST2.
              IF( VDPMODETEXT2 = '1' ) THEN
                PREPATTERN <= PRAMDAT;
              END IF;
            WHEN OTHERS =>
              NULL;
          END CASE;
        WHEN OTHERS => NULL;
      END CASE;

      -- COLOR CODE DECISION
      -- JP: "01"と"10"のタイミングでかラーコーォひ衆力してあげぬば、
      -- JP: VDPエンウィウィの保でケレィエひェコーォして色ひ衆力してくぬに。
      -- JP: "01"と"10"で同じ色ひ衆力すぬば横256ォィエになな、庵う色ひ
      -- JP: 衆力すぬば横512ォィエ表示となに。
      CASE DOTSTATE IS
        WHEN "00" =>
          IF( DOTCOUNTER24(2 DOWNTO 0) = "100" ) THEN
            -- LOAD NEXT 8 DOT DATA
            -- JP: キャラクタの描家は DOTCOUNTER24が、
            -- JP:   "0:4"かど"1:3"の6ォィエ
            -- JP:   "1:4"かど"2:3"の6ォィエ
            -- JP:   "2:4"かど"3:3"の6ォィエ
            -- JP:   "3:4"かど"0:3"の6ォィエ
            -- JP: で拘はぬにので"100"のタイミングでローォすに
            PATTERN <= PREPATTERN;
          ELSIF( (DOTCOUNTER24(2 DOWNTO 0) = "001") AND (VDPMODETEXT2 = '1') ) THEN
            -- JP: TEXT2では"001"のタイミングでぢローォすに。
            PATTERN <= PREPATTERN;
          END IF;
          IF( (DOTCOUNTER24(2 DOWNTO 0) = "100") OR
              (DOTCOUNTER24(2 DOWNTO 0) = "001") ) THEN
            -- EVALUATE BLINK SIGNAL
            IF(DOTCOUNTER24(4 DOWNTO 0) = "00100") THEN
              BLINK <= PREBLINK;
            ELSE
              BLINK <= BLINK(6 DOWNTO 0) & "0";
            END IF;
          END IF;
        WHEN "01" =>
          -- ケターンに猿じてカラーコーォひ決鎚
          TXCOLORCODE <= PATTERN(7);
          -- ケターンひシサエ
          PATTERN <= PATTERN(6 DOWNTO 0) & '0';
        WHEN "11" =>
          NULL;
        WHEN "10" =>
          IF( VDPMODETEXT2 = '1' ) THEN
            TXCOLORCODE <= PATTERN(7);
            -- ケターンひシサエ
            PATTERN <= PATTERN(6 DOWNTO 0) & '0';
          END IF;

        WHEN OTHERS => NULL;
      END CASE;
    END IF;

    --
    -- BLINK TIMING GENERATION
    --
    IF( (DOTCOUNTERX = 0) AND (DOTCOUNTERY = 0) AND (DOTSTATE = "00") ) THEN
      IF (BLINKFRAMECOUNT = "1001") THEN
        BLINKFRAMECOUNTISMAX := '1';
        BLINKFRAMECOUNT <= (OTHERS => '0');
      ELSE
        BLINKFRAMECOUNTISMAX := '0';
        BLINKFRAMECOUNT <= BLINKFRAMECOUNT + 1;
      END IF;

      IF (BLINKFRAMECOUNTISMAX = '1') THEN
        IF( VDPR13BLINKPERIOD(7 DOWNTO 4) = "0000" ) THEN
          -- WHEN ON PERIOD IS 0, THE BLINK COLOR IS ALWAYS OFF
          BLINKSTATE <= '0';
        ELSIF( VDPR13BLINKPERIOD(3 DOWNTO 0) = "0000") THEN
          -- WHEN OFF PERIOD IS 0, THE BLINK COLOR IS ALWAYS ON
          BLINKSTATE <= '1';
        ELSIF( (BLINKSTATE = '0') AND (BLINKPERIODCOUNT >= VDPR13BLINKPERIOD(3 DOWNTO 0)) ) THEN
          BLINKSTATE <= '1';
          BLINKPERIODCOUNT <= (OTHERS => '0');
        ELSIF( (BLINKSTATE = '1') AND (BLINKPERIODCOUNT >= VDPR13BLINKPERIOD(7 DOWNTO 4)) ) THEN
          BLINKSTATE <= '0';
          BLINKPERIODCOUNT <= (OTHERS => '0');
        END IF;
      END IF;
    END IF;

  END PROCESS;
END RTL;
