Apple1_MiST/rtl/tms9918/vdp18/vdp18_ctrl.vhd

375 lines
12 KiB
VHDL

-------------------------------------------------------------------------------
--
-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A.
--
-- $Id: vdp18_ctrl.vhd,v 1.26 2006/06/18 10:47:01 arnim Exp $
--
-- Timing Controller
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised 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 synthesized 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.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software 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 AUTHOR 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.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vdp18_pack.opmode_t;
use work.vdp18_pack.hv_t;
use work.vdp18_pack.access_t;
entity vdp18_ctrl is
port (
clk_i : in std_logic;
clk_en_5m37_i : in boolean;
reset_i : in boolean;
opmode_i : in opmode_t;
num_pix_i : in hv_t;
num_line_i : in hv_t;
vert_inc_i : in boolean;
reg_blank_i : in boolean;
reg_size1_i : in boolean;
stop_sprite_i : in boolean;
clk_en_acc_o : out boolean;
access_type_o : out access_t;
vert_active_o : out boolean;
hor_active_o : out boolean;
irq_o : out boolean
);
end vdp18_ctrl;
use work.vdp18_pack.all;
architecture rtl of vdp18_ctrl is
-----------------------------------------------------------------------------
-- This enables a workaround for a bug in XST.
-- ISE 8.1.02i implements wrong functionality otherwise :-(
--
constant xst_bug_wa_c : boolean := true;
--
-----------------------------------------------------------------------------
signal access_type_s : access_t;
-- pragma translate_off
-- Testbench signals --------------------------------------------------------
--
signal ac_s : std_logic_vector(3 downto 0);
--
-----------------------------------------------------------------------------
-- pragma translate_on
signal vert_active_q,
hor_active_q : boolean;
signal sprite_active_q : boolean;
signal sprite_line_act_q : boolean;
begin
-- pragma translate_off
-- Testbench signals --------------------------------------------------------
--
ac_s <= enum_to_vec_f(access_type_s);
--
-----------------------------------------------------------------------------
-- pragma translate_on
-----------------------------------------------------------------------------
-- Process decode_access
--
-- Purpose:
-- Decode horizontal counter value to access type.
--
decode_access: process (opmode_i,
num_pix_i,
vert_active_q,
sprite_line_act_q,
reg_size1_i)
variable num_pix_plus_6_v : hv_t;
variable mod_6_v : hv_t;
variable num_pix_plus_8_v : hv_t;
variable num_pix_plus_32_v : hv_t;
variable num_pix_spr_v : integer;
begin
-- default assignment
access_type_s <= AC_CPU;
-- prepare number of pixels for pattern operations
num_pix_plus_6_v := num_pix_i + 6;
num_pix_plus_8_v := num_pix_i + 8;
num_pix_plus_32_v := num_pix_i + 32;
num_pix_spr_v := to_integer(num_pix_i and "111111110");
case opmode_i is
-- Graphics I, II and Multicolor Mode -----------------------------------
when OPMODE_GRAPH1 |
OPMODE_GRAPH2 |
OPMODE_MULTIC =>
--
-- Patterns
--
if vert_active_q then
if num_pix_plus_8_v(0) = '0' then
if not xst_bug_wa_c then
-- original code, we want this
case num_pix_plus_8_v(6 to 7) is
when "01" =>
access_type_s <= AC_PNT;
when "10" =>
if opmode_i /= OPMODE_MULTIC then
-- no access to pattern color table in multicolor mode
access_type_s <= AC_PCT;
end if;
when "11" =>
access_type_s <= AC_PGT;
when others =>
null;
end case;
else
-- workaround for XST bug, we need this
if num_pix_plus_8_v(6 to 7) = "01" then
access_type_s <= AC_PNT;
elsif num_pix_plus_8_v(6 to 7) = "10" then
if opmode_i /= OPMODE_MULTIC then
access_type_s <= AC_PCT;
end if;
elsif num_pix_plus_8_v(6 to 7) = "11" then
access_type_s <= AC_PGT;
end if;
end if;
end if;
end if;
--
-- Sprite test
--
if sprite_line_act_q then
if num_pix_i(0) = '0' and
num_pix_i(0 to 5) /= "011111" and
num_pix_i(6 to 7) = "00" and
num_pix_i(4 to 5) /= "00" then
-- sprite test interleaved with pattern accesses - 23 slots
access_type_s <= AC_STST;
end if;
if num_pix_plus_32_v(0 to 4) = "00000" or
num_pix_plus_32_v(0 to 7) = "00001000" then
-- sprite tests before starting pattern phase - 9 slots
access_type_s <= AC_STST;
end if;
--
-- Sprite Attribute Table and Sprite Pattern Table
--
case num_pix_spr_v is
when 250 | -78 |
-62 | -46 =>
access_type_s <= AC_SATY;
when 254 | -76 |
-60 | -44 =>
access_type_s <= AC_SATX;
when 252 | -74 |
-58 | -42 =>
access_type_s <= AC_SATN;
when -86 | -70 |
-54 | -38 =>
access_type_s <= AC_SATC;
when -84 | -68 |
-52 | -36 =>
access_type_s <= AC_SPTH;
when -82 | -66 |
-50 | -34 =>
if reg_size1_i then
access_type_s <= AC_SPTL;
end if;
when others =>
null;
end case;
end if;
-- Text Mode ------------------------------------------------------------
when OPMODE_TEXTM =>
if vert_active_q and
num_pix_plus_6_v(0) = '0' and
num_pix_plus_6_v(0 to 4) /= "01111" then
mod_6_v := mod_6_f(num_pix_plus_6_v);
case mod_6_v(6 to 7) is
when "00" =>
access_type_s <= AC_PNT;
when "10" =>
access_type_s <= AC_PGT;
when others =>
null;
end case;
end if;
-- Unknown --------------------------------------------------------------
when others =>
null;
end case;
end process decode_access;
--
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Process vert_flags
--
-- Purpose:
-- Track the vertical position with flags.
--
vert_flags: process (clk_i, reset_i)
begin
if reset_i then
vert_active_q <= false;
sprite_active_q <= false;
sprite_line_act_q <= false;
elsif clk_i'event and clk_i = '1' then
if clk_en_5m37_i then
-- line-local sprite processing
if sprite_active_q then
-- sprites are globally enabled
if vert_inc_i then
-- reload at beginning of every new line
-- => scan with STST
sprite_line_act_q <= true;
end if;
if num_pix_i = hv_sprite_start_c then
-- reload when access to sprite memory starts
sprite_line_act_q <= true;
end if;
end if;
if vert_inc_i then
-- global sprite processing
if reg_blank_i then
sprite_active_q <= false;
sprite_line_act_q <= false;
elsif num_line_i = -2 then
-- start at line -1
sprite_active_q <= true;
-- initialize immediately
sprite_line_act_q <= true;
elsif num_line_i = 191 then
-- stop at line 192
sprite_active_q <= false;
-- force stop
sprite_line_act_q <= false;
end if;
-- global vertical display
if reg_blank_i then
vert_active_q <= false;
elsif num_line_i = -1 then
-- start vertical display at line 0
vert_active_q <= true;
elsif num_line_i = 191 then
-- stop at line 192
vert_active_q <= false;
end if;
end if;
if stop_sprite_i then
-- stop processing of sprites in this line
sprite_line_act_q <= false;
end if;
end if;
end if;
end process vert_flags;
--
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Process hor_flags
--
-- Purpose:
-- Track the horizontal position.
--
hor_flags: process (clk_i, reset_i)
begin
if reset_i then
hor_active_q <= false;
elsif clk_i'event and clk_i = '1' then
if clk_en_5m37_i then
if not reg_blank_i and
num_pix_i = -1 then
hor_active_q <= true;
end if;
if opmode_i = OPMODE_TEXTM then
if num_pix_i = 239 then
hor_active_q <= false;
end if;
else
if num_pix_i = 255 then
hor_active_q <= false;
end if;
end if;
end if;
end if;
end process hor_flags;
--
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Ouput mapping
-----------------------------------------------------------------------------
-- generate clock enable for flip-flops working on access_type
clk_en_acc_o <= clk_en_5m37_i and num_pix_i(8) = '1';
access_type_o <= access_type_s;
vert_active_o <= vert_active_q;
hor_active_o <= hor_active_q;
irq_o <= vert_inc_i and num_line_i = 191;
end rtl;