Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dansanderson/24cc54b111a9db144f783bfc1016767a to your computer and use it in GitHub Desktop.
Save dansanderson/24cc54b111a9db144f783bfc1016767a to your computer and use it in GitHub Desktop.
--
-- Written by
-- Paul Gardner-Stephen <[email protected]> 2013-2014
--
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU Lesser General Public License as
-- * published by the Free Software Foundation; either version 3 of the
-- * License, or (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU General Public License for more details.
-- *
-- * You should have received a copy of the GNU Lesser General Public License
-- * along with this program; if not, write to the Free Software
-- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-- * 02111-1307 USA.
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 19:11:30 01/02/2014
-- Design Name:
-- Module Name: vga - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
use Std.TextIO.all;
use work.debugtools.all;
use work.victypes.all;
use work.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity viciv is
generic (
chipram_size : integer := 393216;
hyper_installed : boolean := false
);
Port (
all_pause : in std_logic;
hypervisor_mode : in std_logic;
hw_errata_level : in unsigned(7 downto 0);
hw_errata_enable_toggle : inout std_logic;
hw_errata_disable_toggle : inout std_logic;
xcounter_out : out integer range 0 to 4095 := 0;
ycounter_out : out integer range 0 to 2047 := 0;
----------------------------------------------------------------------
-- dot clock
----------------------------------------------------------------------
pixelclock : in STD_LOGIC;
----------------------------------------------------------------------
-- CPU clock (used for chipram and fastio interfaces)
----------------------------------------------------------------------
cpuclock : in std_logic;
-- CPU IRQ
irq : out std_logic;
reset : in std_logic;
dd00_bits : in unsigned(1 downto 0);
upscale_enable : out std_logic := '0';
-- Touch event to simulate light pen
touch_x : in unsigned(13 downto 0);
touch_y : in unsigned(11 downto 0);
touch_active : in std_logic := '0';
-- Internal drive LED status for OSD
led : in std_logic;
motor : in std_logic;
-- Actual drive LED (including blink status) for keyboard
-- (the F011 does this on a real C65)
drive_led_out : out std_logic;
vicii_2mhz : out std_logic;
viciii_fast : out std_logic;
viciv_fast : out std_logic;
viciv_frame_indicate : out std_logic := '0';
interlace_mode : out std_logic := '0';
mono_mode : out std_logic := '0';
-- Used to tell the CPU when to steal cycles to simulate badlines
badline_toggle : out std_logic := '0';
vicii_raster_out : out unsigned(11 downto 0) := to_unsigned(0,12);
d031_written : out std_logic;
xray_mode : in std_logic;
test_pattern_enable : buffer std_logic := '0';
dat_even : out std_logic;
dat_offset : out unsigned(15 downto 0);
dat_bitplane_bank : out unsigned(2 downto 0) := "000";
dat_bitplane_addresses : out sprite_vector_eight;
-- Used to synchronise our frame with an external frame generator
-- (Used to provide stable frame generation for LCD displays, as well
-- as to support a genlock input).
external_frame_x_zero : in std_logic;
external_frame_y_zero : in std_logic := '0';
-- Similarly, we get told when we should be presenting a new pixel, so
-- that we don't have to figure out all the fiddly timing ourselves
external_pixel_strobe_in : in std_logic := '0';
----------------------------------------------------------------------
-- VGA output
----------------------------------------------------------------------
vsync_polarity : out STD_LOGIC := '0';
hsync_polarity : out STD_LOGIC := '0';
pal50_select : out std_logic := '0';
vga60_select : out std_logic := '0';
lcd_pixel_strobe : out std_logic;
vga_in_frame : in std_logic;
vgared : out UNSIGNED (7 downto 0);
vgagreen : out UNSIGNED (7 downto 0);
vgablue : out UNSIGNED (7 downto 0);
viciv_outofframe : out std_logic := '0';
pixel_stream_out : out unsigned (7 downto 0);
pixel_red_out : out unsigned (7 downto 0);
pixel_green_out : out unsigned (7 downto 0);
pixel_blue_out : out unsigned (7 downto 0);
pixel_y : out unsigned (11 downto 0) := (others => '0');
pixel_x_out : out integer := 0;
pixel_strobe_out : out std_logic;
pixel_newframe : out std_logic;
pixel_frame_toggle : buffer std_logic;
pixel_newraster : out std_logic;
-- Pixel x counter scaled to count to about 640
pixel_x_640 : out integer := 0;
-- And as above, but with the 800 pixel resolution.
pixel_x_800 : out integer := 0;
-- And pixel X counter scaled to actual video mode (typically 800)
-- (and corrected for video pipeline depth)
-- This one holds at zero until the first VIC-II/III sprite position in the
-- left border.
native_x_640 : out integer := 0;
native_y_200 : out integer := 0;
native_y_400 : out integer := 0;
-- Scale for 200 and 400px high modes (used by compositors)
pixel_y_scale_400 : out unsigned(3 downto 0) := (others => '0');
pixel_y_scale_200 : out unsigned(3 downto 0) := (others => '0');
---------------------------------------------------------------------------
-- CPU Interface to ChipRAM in video controller (allow upto 1MB)
---------------------------------------------------------------------------
--chipram_we : IN STD_LOGIC;
chipram_address : OUT unsigned(19 DOWNTO 0);
chipram_datain : IN unsigned(7 DOWNTO 0);
---------------------------------------------------------------------------
-- Direct interface to HyperRAM for fetching 256 colour glyph data etc
---------------------------------------------------------------------------
hyper_addr : out unsigned(18 downto 3) := (others => '0');
hyper_request_toggle : out std_logic := '0';
hyper_data_in : in unsigned(7 downto 0) := x"00";
hyper_data_strobe_in : in std_logic := '0';
-----------------------------------------------------------------------------
-- FastIO interface for accessing video registers
-----------------------------------------------------------------------------
fastio_addr : in std_logic_vector(19 downto 0);
fastio_read : in std_logic;
fastio_write : in std_logic;
fastio_wdata : in std_logic_vector(7 downto 0);
fastio_rdata : out std_logic_vector(7 downto 0);
colour_ram_fastio_rdata : out std_logic_vector(7 downto 0);
colour_ram_cs : in std_logic;
charrom_fastio_rdata : out std_logic_vector(7 downto 0);
charrom_cs : in std_logic;
viciii_iomode : out std_logic_vector(1 downto 0) := "11";
iomode_set : in std_logic_vector(1 downto 0);
iomode_set_toggle : in std_logic;
colourram_at_dc00 : out std_logic := '0';
rom_at_e000 : out std_logic;
rom_at_c000 : out std_logic;
rom_at_a000 : out std_logic;
rom_at_8000 : out std_logic
);
end viciv;
architecture Behavioral of viciv is
signal reset_drive : std_logic := '0';
signal bitplane_bank_select : unsigned(2 downto 0) := "000";
signal iomode_set_toggle_last : std_logic := '0';
signal before_y_chargen_start : std_logic := '1';
signal justbefore_y_chargen_start : std_logic := '0';
signal stop_chargen_raster_counter : unsigned(7 downto 0) := x"00";
signal stop_chargen_delay : unsigned(7 downto 0) := to_unsigned(3,8);
signal vicii_2mhz_internal : std_logic := '1';
signal viciii_fast_internal : std_logic := '1';
signal viciv_fast_internal : std_logic := '1';
signal viciv_bitplane_chargen_on : std_logic := '0';
signal reg_xcounter_delay : integer range 0 to 31 := 4;
signal xcounter_pipeline_delayed : integer := 0;
signal external_pixel_strobe_log : std_logic_vector(31 downto 0) := (others => '0');
signal sprite_h640_delayed : std_logic := '0';
signal sprite_v400s_delayed : std_logic_vector(7 downto 0) := x"00";
signal reg_h640_delayed : std_logic := '0';
signal reg_h1280_delayed : std_logic := '0';
signal external_frame_x_zero_latched : std_logic := '0';
signal last_external_frame_x_zero_latched : std_logic := '0';
signal last_external_frame_y_zero : std_logic := '0';
-- last value written to key register
signal reg_key : unsigned(7 downto 0) := x"00";
signal last_dd00_bits : unsigned(1 downto 0) := "11";
signal vicii_hot_regs_enable : std_logic := '1';
signal viciv_legacy_mode_registers_touched : std_logic := '0';
signal viciv_single_side_border_width_touched : std_logic := '0';
signal reg_d018_screen_addr : unsigned(3 downto 0) := x"1";
signal bump_screen_row_address : std_logic := '0';
-- Drive stage for IRQ signal in attempt to allieviate timing problems.
signal irq_drive : std_logic := '1';
-- Buffer VGA signal to save some time. Similarly pipeline
-- palette lookup.
signal vga_buffer_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer_blue : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer2_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer2_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer2_blue : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer3_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer3_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer3_blue : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer4_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer4_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer4_blue : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer5_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer5_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_buffer5_blue : UNSIGNED (7 downto 0) := (others => '0');
signal vga_filtered_red : UNSIGNED (9 downto 0) := (others => '0');
signal vga_filtered_green : UNSIGNED (9 downto 0) := (others => '0');
signal vga_filtered_blue : UNSIGNED (9 downto 0) := (others => '0');
signal vga_palin_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_palin_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_palin_blue : UNSIGNED (7 downto 0) := (others => '0');
signal vga_palout_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_palout_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_palout_blue : UNSIGNED (7 downto 0) := (others => '0');
signal vga_out_red : UNSIGNED (7 downto 0) := (others => '0');
signal vga_out_green : UNSIGNED (7 downto 0) := (others => '0');
signal vga_out_blue : UNSIGNED (7 downto 0) := (others => '0');
signal pixel_colour : unsigned(7 downto 0) := x"00";
signal pixel_alpha : unsigned(7 downto 0) := x"00";
-- Select which of the four video modes to use at any point in time.
signal vicii_ntsc : std_logic := '1';
signal vga60_select_internal : std_logic := '0';
-- Video mode definition
-- NOTE: These get overwritten by $D06F PAL/NTSC flags
-- The values here are simply those that apply on power up.
-- NOTE: frame_h_front is deprecated due to the pixel_driver now?
-- In any case, it seems to cause the trimming of frame_h_front pixels
constant frame_h_front : unsigned(7 downto 0) := to_unsigned(0,8);
-- 800x480 @ 50Hz for 100MHz pixelclock
signal single_side_border : unsigned(13 downto 0) := to_unsigned(80,14);
constant display_width : unsigned(11 downto 0) := to_unsigned(800,12);
-- We double-buffer the rendering of chargen raster data, so that we can begin
-- the fetch early. We just need to allow a few pixels after xcount=0 to let
-- things get started.
-- (Sprite fetching should happen as soon as the border begins, so that we have
-- maximum time to do the fetch.)
constant display_fetch_start : unsigned(11 downto 0) := to_unsigned(719,12);
constant display_height_pal : unsigned(11 downto 0) := to_unsigned(623-20,12);
constant display_height_ntsc : unsigned(11 downto 0) := to_unsigned(526-20,12);
signal display_height : unsigned(11 downto 0);
signal raster_buffer_half_toggle : std_logic := '0';
signal vicii_ycounter_scale_minus_zero : unsigned(3 downto 0) := to_unsigned(2-1,4);
signal chargen_x_scale : unsigned(7 downto 0) := to_unsigned(120,8);
signal sprite_first_x : unsigned(13 downto 0) := to_unsigned(31,14);
signal sprite_y_adjust : unsigned(7 downto 0) := to_unsigned(0,8);
signal sprite_x_counting : std_logic := '0';
signal sprite_x_scale_toggle : std_logic := '0';
-- Each character pixel will be (n+1) pixels high
signal chargen_y_scale : unsigned(7 downto 0) := x"01"; -- x"04"
-- smooth scrolling position in natural pixels.
-- Set in the same way as the border
signal x_chargen_start : unsigned(13 downto 0) := to_unsigned(safe_to_integer(frame_h_front),14);
-- PAL/NTSC raster layout
signal vicii_first_raster : unsigned(8 downto 0) := to_unsigned(0,9);
constant ntsc_max_raster : unsigned(8 downto 0) := to_unsigned(262,9);
constant pal_max_raster : unsigned(8 downto 0) := to_unsigned(312,9);
signal vicii_max_raster : unsigned(8 downto 0) := pal_max_raster;
-- Setting this value positive causes the chargen and screen to move down the
-- screen relative to the VIC-II raster counter.
constant raster_correction : integer := 3;
-- Calculated dynamically
signal x_end_of_raster : unsigned(13 downto 0) := to_unsigned(0,14);
signal vicii_ycounter_scale : unsigned(3 downto 0) := to_unsigned(0,4);
constant frame_v_front : integer := 1;
-- Frame generator counters
-- DEBUG: Start frame at a point that will soon trigger a badline
signal xcounter : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_last : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_delayed : unsigned(13 downto 0) := to_unsigned(0,14);
-- Pipeline delay for export of xcounter
signal xcounter_17 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_16 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_15 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_14 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_13 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_12 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_11 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_10 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_9 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_8 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_7 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_6 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_5 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_4 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_3 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_2 : unsigned(13 downto 0) := to_unsigned(0,14);
signal xcounter_1 : unsigned(13 downto 0) := to_unsigned(0,14);
signal ycounter_last : unsigned(13 downto 0) := to_unsigned(0,14);
signal ycounter_export_countdown : integer range 0 to 31 := 0;
signal xcounter_drive : unsigned(13 downto 0) := (others => '0');
signal ycounter : unsigned(11 downto 0) := to_unsigned(625,12);
signal ycounter_drive : unsigned(11 downto 0) := (others => '0');
signal last_ycounter : unsigned(11 downto 0) := to_unsigned(625,12);
-- Virtual raster number for VIC-II
-- (On powerup set to a PAL only raster so that ROM doesn't need to wait a
-- whole frame. This is really just to make testing through simulation quicker
-- since a whole frame takes ~20 minutes to simulate).
signal vicii_ycounter : unsigned(8 downto 0) := to_unsigned(0,9);
signal vicii_ycounter_continuous : unsigned(8 downto 0) := to_unsigned(0,9);
signal vicii_ycounter_driver : unsigned(8 downto 0) := to_unsigned(0,9);
signal vicii_ycounter_minus_one : unsigned(8 downto 0) := to_unsigned(0,9);
signal vicii_sprite_ycounter : unsigned(8 downto 0) := to_unsigned(0,9);
signal vicii_ycounter_v400 : unsigned(9 downto 0) := to_unsigned(0,10);
signal last_vicii_ycounter : unsigned(8 downto 0) := to_unsigned(0,9);
signal vicii_ycounter_phase : unsigned(3 downto 0) := (others => '0');
signal vicii_ycounter_max_phase : unsigned(3 downto 0) := (others => '0');
signal vicii_ycounter_phase_v400 : unsigned(3 downto 0) := (others => '0');
signal vicii_ycounter_max_phase_v400 : unsigned(3 downto 0) := (others => '0');
-- Is the VIC-II virtual raster number the active one for interrupts, or
-- are we comparing to physical rasters? This is decided by which register
-- gets written to last.
signal vicii_is_raster_source : std_logic := '1';
signal vicii_xcounter_320 : unsigned(8 downto 0) := (others => '0');
signal vicii_xcounter_640 : unsigned(9 downto 0) := (others => '0');
signal last_vicii_xcounter_640 : unsigned(9 downto 0) := (others => '0');
-- Actual pixel positions in the frame
signal displayy : unsigned(11 downto 0) := to_unsigned(0,12);
-- Mark if we are in the top line of display
-- (used for overlaying drive LED on first row of pixels)
signal displayline0 : std_logic := '1';
signal displaycolumn0 : std_logic := '1';
-- Asserted if in the displayed part of vertical frame
-- DEBUG: Power up with in frame to make simulation in ghdl much quicker.
signal vert_in_frame : std_logic := '1';
-- Used for counting down cycles while waiting for RAM to respond
signal delay : std_logic_vector(1 downto 0) := "00";
-- Interface to buffer for screen ram (converts 64 bits wide to 8 bits
-- wide for us)
signal screen_ram_buffer_write : std_logic := '0';
signal screen_ram_buffer_read_address : unsigned(9 downto 0) := to_unsigned(0,10);
signal screen_ram_buffer_write_address : unsigned(9 downto 0) := to_unsigned(0,10);
signal screen_ram_buffer_din : unsigned(7 downto 0) := x"00";
signal screen_ram_buffer_dout : unsigned(7 downto 0) := x"00";
-- Internal registers used to keep track of the screen ram for the current row
signal screen_row_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal screen_row_current_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal full_colour_fetch_count : integer range 0 to 8 := 0;
signal full_colour_data : unsigned(63 downto 0) := (others => '0');
signal paint_full_colour_data : unsigned(63 downto 0) := (others => '0');
signal paint_alternate_palette : std_logic := '0';
-- chipram access management registers
signal next_ramaddress : unsigned(19 downto 0) := to_unsigned(0,20);
signal next_ramaccess_is_screen_row_fetch : std_logic := '0';
signal this_ramaccess_is_screen_row_fetch : std_logic := '0';
signal last_ramaccess_is_screen_row_fetch : std_logic := '0';
signal final_ramaccess_is_screen_row_fetch : std_logic := '0';
signal next_ramaccess_is_glyph_data_fetch : std_logic := '0';
signal this_ramaccess_is_glyph_data_fetch : std_logic := '0';
signal last_ramaccess_is_glyph_data_fetch : std_logic := '0';
signal final_ramaccess_is_glyph_data_fetch : std_logic := '0';
signal next_ramaccess_is_sprite_data_fetch : std_logic := '0';
signal this_ramaccess_is_sprite_data_fetch : std_logic := '0';
signal last_ramaccess_is_sprite_data_fetch : std_logic := '0';
signal final_ramaccess_is_sprite_data_fetch : std_logic := '0';
signal this_ramaccess_screen_row_buffer_address : unsigned(9 downto 0) := to_unsigned(0,10);
signal next_ramaccess_screen_row_buffer_address : unsigned(9 downto 0) := to_unsigned(0,10);
signal last_ramaccess_screen_row_buffer_address : unsigned(9 downto 0) := to_unsigned(0,10);
signal final_ramaccess_screen_row_buffer_address : unsigned(9 downto 0) := to_unsigned(0,10);
signal next_screen_row_fetch_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal this_screen_row_fetch_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal last_screen_row_fetch_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal final_screen_row_fetch_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal final_ramdata : unsigned(7 downto 0) := to_unsigned(0,8);
signal vgared_driver : unsigned(7 downto 0) := x"00";
signal vgablue_driver : unsigned(7 downto 0) := x"00";
signal vgagreen_driver : unsigned(7 downto 0) := x"00";
signal ycounter_driver : unsigned(11 downto 0) := to_unsigned(625,12);
-- Internal registers for drawing a single raster of character data to the
-- raster buffer.
signal character_number : unsigned(10 downto 0) := to_unsigned(0,11);
type vic_chargen_fsm is (Idle,
FetchScreenRamLine,
FetchScreenRamLine2,
FetchScreenRamNext,
FetchFirstCharacter,
FetchNextCharacter,
FetchCharHighByte,
FetchTextCell,
FetchTextCellColourAndSource,
FetchBitmapCell,
FetchBitmapData,
PaintFullColourFetch,
PaintFullColourHyperRAMFetch,
PaintMemWait,
PaintMemWait2,
PaintMemWait3,
PaintDispatch,
EndOfChargen,
SpritePointerFetch,
SpritePointerFetch2,
SpritePointerCompute1,
SpritePointerCompute,
SpritePointerComputeMSB,
SpriteDataFetch,
SpriteDataFetch2);
signal raster_fetch_state : vic_chargen_fsm := Idle;
type vic_paint_fsm is (Idle,
PaintFullColour,Paint4bitColourPixels,PaintFullColourPixels,PaintFullColourDone,
PaintMono,PaintMonoDrive,PaintMonoBits,
PaintMultiColour,PaintMultiColourDrive,
PaintMultiColourBits,PaintMultiColourHold);
signal paint_fsm_state : vic_paint_fsm := Idle;
signal paint_ready : std_logic := '0';
signal paint_from_charrom : std_logic := '0';
signal paint_flip_horizontal : std_logic := '0';
signal paint_foreground : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_background : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_mc1 : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_mc2 : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_buffer_hflip_chardata : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_buffer_noflip_chardata : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_buffer_hflip_ramdata : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_buffer_noflip_ramdata : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_buffer : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_bits_remaining : integer range 0 to 16 := 0;
signal paint_chardata : unsigned(7 downto 0) := to_unsigned(0,8);
signal paint_ramdata : unsigned(7 downto 0) := to_unsigned(0,8);
signal horizontal_filter : std_logic := '1';
signal pal_simulate : std_logic := '0';
signal shadow_mask_enable : std_logic := '0';
signal upscale_enable_int : std_logic := '0';
signal debug_x : unsigned(13 downto 0) := "11111111111110";
signal debug_y : unsigned(11 downto 0) := "111111111110";
signal debug_pixel_red : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_pixel_green : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_pixel_blue : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_channel_select : std_logic_vector(1 downto 0) := "00";
signal debug_screen_ram_buffer_address : unsigned(9 downto 0) := to_unsigned(0,10);
signal debug_raster_buffer_read_address : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_raster_buffer_write_address : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_cycles_to_next_card : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_raster_fetch_state : vic_chargen_fsm := Idle;
signal debug_paint_fsm_state : vic_paint_fsm := Idle;
signal debug_chargen_active : std_logic := '0';
signal debug_chargen_active_soon : std_logic := '0';
signal debug_character_data_from_rom : std_logic := '0';
signal debug_charaddress : unsigned(11 downto 0) := to_unsigned(0,12);
signal debug_charrow : std_logic_vector(7 downto 0) := x"00";
signal debug_screen_ram_buffer_address_drive : unsigned(9 downto 0) := to_unsigned(0,10);
signal debug_cycles_to_next_card_drive : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_raster_fetch_state_drive : vic_chargen_fsm := Idle;
signal debug_paint_fsm_state_drive : vic_paint_fsm := Idle;
signal debug_chargen_active_drive : std_logic := '0';
signal debug_chargen_active_soon_drive : std_logic := '0';
signal debug_character_data_from_rom_drive : std_logic := '0';
signal debug_charaddress_drive : unsigned(11 downto 0) := to_unsigned(0,12);
signal debug_charrow_drive : std_logic_vector(7 downto 0) := x"00";
signal debug_raster_buffer_read_address_drive : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_raster_buffer_write_address_drive : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_screen_ram_buffer_address_drive2 : unsigned(9 downto 0) := to_unsigned(0,10);
signal debug_raster_buffer_read_address_drive2 : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_raster_buffer_write_address_drive2 : unsigned(7 downto 0) := to_unsigned(0,8);
signal debug_raster_fetch_state_drive2 : vic_chargen_fsm := Idle;
signal debug_paint_fsm_state_drive2 : vic_paint_fsm := Idle;
signal debug_chargen_active_drive2 : std_logic := '0';
signal debug_chargen_active_soon_drive2 : std_logic := '0';
signal debug_character_data_from_rom_drive2 : std_logic := '0';
signal debug_charaddress_drive2 : unsigned(11 downto 0) := to_unsigned(0,12);
signal debug_charrow_drive2 : std_logic_vector(7 downto 0) := x"00";
-----------------------------------------------------------------------------
-- Video controller registers
-----------------------------------------------------------------------------
-- New control registers
-- These next two can be used to make a screen which is a huge playfield with
-- just a portion visible at any point in time.
-- Number added to card number for each row of characters, i.e., how many bytes
-- should we skip as we advance each row.
signal virtual_row_width : unsigned(15 downto 0) := to_unsigned(40,16);
-- And display_row_width is how many characters to display on each row
signal display_row_width : unsigned(9 downto 0) := to_unsigned(40,10);
signal display_row_width_minus1 : unsigned(9 downto 0) := to_unsigned(40,10);
signal display_row_count : unsigned(7 downto 0) := to_unsigned(25-1,8);
signal display_row_number : unsigned(7 downto 0) := to_unsigned(25,8);
signal end_of_row_16 : std_logic := '0';
signal end_of_row : std_logic := '0';
signal chargen_x_scale_drive : unsigned(7 downto 0) := to_unsigned(0,8);
signal x_chargen_start_minus1 : unsigned(13 downto 0) := to_unsigned(0,14);
-- DEBUG: Start character generator in first raster on power up to make ghdl
-- simulation much quicker
signal y_chargen_start : unsigned(11 downto 0) := to_unsigned(1,12); -- 0
signal y_chargen_start_minus_one : unsigned(11 downto 0) := to_unsigned(0,12); --
--auto-calculated signal
-- Charset is 16bit (2 bytes per char) when this mode is enabled.
signal sixteenbit_charset : std_logic := '1';
-- Characters >255 are full-colour blocks when enabled.
signal fullcolour_extendedchars : std_logic := '1';
-- Characters <256 are full-colour blocks when enabled
signal fullcolour_8bitchars : std_logic := '1';
-- Optionally fetch full-colour chars from HyperRAM
signal glyphs_from_hyperram : std_logic := '0';
-- VIC-II style Mode control bits (correspond to bits in $D016 etc)
-- -- Text/graphics mode select
signal text_mode : std_logic := '1';
-- -- Basic multicolour mode bit
signal multicolour_mode : std_logic := '0';
-- -- Enable 256 colours in multicolour text mode
signal fullcolour_mcm : std_logic := '0';
-- -- Extended background colour mode (reduces charset to 64 entries)
signal extended_background_mode : std_logic := '0';
-- Border dimensions
-- DEBUG: No top or left borders on power up to make ghdl simulation of frame
-- drawing much quicker.
signal border_x_left : unsigned(13 downto 0) := to_unsigned(0,14);
signal border_x_right : unsigned(13 downto 0) := to_unsigned(2000,14);
signal border_y_top : unsigned(11 downto 0) := to_unsigned(1,12);
signal border_y_bottom : unsigned(11 downto 0) := to_unsigned(600,12);
signal blank : std_logic := '0';
-- intermediate calculations for whether we are in the border to improve timing.
signal vertical_border : std_logic := '1';
-- Colour registers ($D020 - $D024)
signal screen_colour : unsigned(7 downto 0) := x"08"; -- orange
signal border_colour : unsigned(7 downto 0) := x"04"; -- green
signal multi1_colour : unsigned(7 downto 0) := x"01"; -- multi-colour mode #1
signal multi2_colour : unsigned(7 downto 0) := x"02"; -- multi-colour mode #2
signal multi3_colour : unsigned(7 downto 0) := x"03"; -- multi-colour mode #3
-- XXX move reading of sprite registers to vicii_sprites module
signal sprite_multi0_colour : unsigned(7 downto 0) := x"04";
signal sprite_multi1_colour : unsigned(7 downto 0) := x"05";
signal sprite_x : sprite_vector_eight := (others => x"02");
signal sprite_y : sprite_vector_eight := (others => x"02");
signal sprite_colours : sprite_vector_eight := (others => x"00");
-- VIC-III bitplane registers
signal bitplane_mode : std_logic := '0';
signal bitplane_enables : std_logic_vector(7 downto 0) := "00000000";
signal bitplane_complements : std_logic_vector(7 downto 0) := "00000000";
signal bitplane_sixteen_colour_mode_flags : std_logic_vector(7 downto 0) := "00000000";
signal bitplanes_x_start : unsigned(7 downto 0) := to_unsigned(0,8);
signal bitplanes_y_start : unsigned(7 downto 0) := to_unsigned(0,8);
signal bitplanes_x_start_drive : unsigned(7 downto 0) := to_unsigned(0,8);
signal bitplanes_y_start_drive : unsigned(7 downto 0) := to_unsigned(0,8);
signal dat_x : unsigned(6 downto 0) := to_unsigned(0,7);
signal dat_y : unsigned(8 downto 0) := to_unsigned(0,9);
signal dat_bitplane_offset : unsigned(15 downto 0) := x"0000";
signal bitplane_addresses : sprite_vector_eight;
signal max_sprite_fetch_byte_number : integer range 0 to 399 := 0;
-- Extended sprite features
signal sprite_extended_height_enables : std_logic_vector(7 downto 0) := "00000000";
signal sprite_extended_height_size : unsigned(7 downto 0) := to_unsigned(21,8);
signal sprite_extended_width_enables : std_logic_vector(7 downto 0) := "00000000";
signal sprite_horizontal_tile_enables : std_logic_vector(7 downto 0) := "00000000";
signal sprite_bitplane_enables : std_logic_vector(7 downto 0) := "00000000";
signal sprite_alpha_blend_enables : std_logic_vector(7 downto 0) := "00000000";
signal sprite_alpha_blend_value : unsigned(7 downto 0) := x"80";
signal sprite_sixteen_colour_enables : std_logic_vector(7 downto 0) := "00000000";
-- VIC-II sprites are in a separate module as a chain. To avoid the need to
-- route to all sprites from the main VIC-IV section, they are arranged as a
-- chain. However, the VIC-IV must perform the memory accesses for the
-- VIC-II sprites. Thus we have a bus that passes through each of these
-- sprites delivering the data they need. We also have a separate bus that
-- delivers the current row number for each sprite so that the VIC-IV knows
-- which bytes of memory to deliver to the sprites. This arrangement allows
-- for normal VIC-II semantics for the sprites, including priority order etc.
-- The only difference we intend to implement here is to have a register that
-- allows the number of rows in each sprite to be varied from the usual 21,
-- since there is no reason to maintain this fairly artificial limit. Even
-- in the VIC-II the only logic cost would have been the extra register (or
-- register per sprite).
--
-- C65 VIC-III bitplanes will be implemented using the same sprite data pipeline
-- so that no further stress is placed on the VIC-IV memory access logic,
-- which is already rather strained at the 192MHz pixel clock.
signal sprite_data_offset_rx : integer range 0 to 65535;
signal sprite_number_counter : integer range 0 to 15 := 0;
signal sprite_number_for_data_tx : integer range 0 to 15 := 0;
signal sprite_number_for_data_rx : integer range 0 to 15;
type sprite_data_offset_8 is array(0 to 15) of integer range 0 to 65535;
signal sprite_data_offsets : sprite_data_offset_8;
-- Similarly we need to deliver the bytes of data to the VIC-II sprite chain
signal sprite_datavalid : std_logic;
signal sprite_bytenumber : spritebytenumber := 0;
signal sprite_spritenumber : spritenumber := 0;
signal sprite_data_byte : unsigned(7 downto 0) := to_unsigned(0,7+1);
-- The sprite chain also has the opportunity to modify the pixel colour being
-- drawn so that the sprites can be overlayed on the display.
signal pixel_is_foreground : std_logic;
signal pixel_is_background : std_logic;
signal pixel_is_foreground_in : std_logic;
signal pixel_is_background_in : std_logic;
signal composite_bg_red : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal composite_bg_green : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal composite_bg_blue : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal composite_red : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal composite_green : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal composite_blue : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal composited_red : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(0,9+1));
signal composited_green : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(0,9+1));
signal composited_blue : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(0,9+1));
signal compositer_enable : std_logic := '1';
signal is_background_in : std_logic;
signal pixel_is_background_out : std_logic;
signal pixel_is_foreground_out : std_logic;
signal chargen_pixel_colour : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal chargen_alpha_value : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal postsprite_pixel_colour : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal postsprite_alpha_value : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal postsprite_sprite_number : integer range 0 to 7;
signal postsprite_alternate_palette : std_logic := '0';
signal postsprite_alternate_palette_delayed : std_logic := '0';
signal alpha_blend_alpha : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal pixel_is_sprite : std_logic;
signal sprite_fetch_drive : std_logic := '0';
signal sprite_fetch_sprite_number : integer range 0 to 31 := 0;
signal sprite_fetch_byte_number : integer range 0 to 319 := 0;
signal sprite_fetch_sprite_number_drive : integer range 0 to 31 := 0;
signal sprite_fetch_byte_number_drive : integer range 0 to 319 := 0;
signal sprite_pointer_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal sprite_data_address : unsigned(19 downto 0) := to_unsigned(0,20);
signal sprite_data_addresses : spritebaseaddresses := (others => to_unsigned(0,20));
signal sprite_h640_msbs : std_logic_vector(7 downto 0) := x"00";
-- Compatibility registers
signal twentyfourlines : std_logic := '0';
signal thirtyeightcolumns : std_logic := '0';
signal vicii_raster_compare : unsigned(10 downto 0) := to_unsigned(256,11);
signal viciv_rasterx_compare : unsigned(13 downto 0) := to_unsigned(8191,14);
signal vicii_raster_compare_plus_one : unsigned(10 downto 0) := to_unsigned(256,11);
signal vicii_x_smoothscroll : unsigned(2 downto 0) := to_unsigned(0,2+1);
signal vicii_y_smoothscroll : unsigned(2 downto 0) := to_unsigned(0,2+1);
-- NOTE: these are here for reading. the actual used VIC-II sprite
-- registers are defined in vicii_sprites.vhdl
signal vicii_sprite_enables : std_logic_vector(7 downto 0) := x"FF";
signal vicii_sprite_xmsbs : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal vicii_sprite_x_expand : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal vicii_sprite_y_expand : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal vicii_sprite_priority_bits : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal vicii_sprite_multicolour_bits : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
-- Here are the signals received from the sprites, which get ored onto
-- the following signals.
signal vicii_sprite_sprite_collision_map : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal vicii_sprite_bitmap_collision_map : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
-- HEre is what gets read from the VIC-II register (and then zeroed in the process)
-- and which also get checked for interrupt generation
signal vicii_sprite_sprite_collisions : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal vicii_sprite_bitmap_collisions : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal viciii_extended_attributes : std_logic := '1';
signal irq_lightpen : std_logic := '0';
signal irq_collisionspritesprite : std_logic := '0';
signal irq_collisionspritebitmap : std_logic := '0';
signal irq_raster : std_logic := '0';
signal irq_rasterx : std_logic := '0';
signal irq_extras_enable : std_logic := '0';
signal ack_lightpen : std_logic := '0';
signal ack_collisionspritesprite : std_logic := '0';
signal ack_collisionspritebitmap : std_logic := '0';
signal ack_raster : std_logic := '0';
signal ack_rasterx : std_logic := '0';
signal mask_lightpen : std_logic := '0';
signal mask_collisionspritesprite : std_logic := '0';
signal mask_collisionspritebitmap : std_logic := '0';
signal mask_raster : std_logic := '0';
signal mask_rasterx : std_logic := '0';
signal clear_collisionspritebitmap : std_logic := '0';
signal clear_collisionspritebitmap_1 : std_logic := '0';
signal clear_collisionspritesprite : std_logic := '0';
signal clear_collisionspritesprite_1 : std_logic := '0';
signal lightpen_x_latch : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal lightpen_y_latch : unsigned(7 downto 0) := to_unsigned(0,7+1);
-- Used for hardware character blinking ala C65
signal viciii_blink_phase : std_logic := '0';
-- 60 frames = 1 second, and means no tearing.
signal viciii_blink_phase_counter : integer range 0 to 30 := 0;
-- And faster version for blinking drive led
signal drive_blink_phase : std_logic := '0';
signal drive_blink_phase_counter : integer range 0 to 15 := 0;
-- NOTE: The following registers require 64-bit alignment. Default addresses
-- are fairly arbitrary.
-- Colour RAM offset (we just use some normal RAM for colour RAM, since in the
-- worst case we can need >32KB of it. Must correspond to a ChipRAM address,
-- so the MSBs are irrelevant.
signal colour_ram_base : unsigned(15 downto 0) := x"0000";
-- Screen RAM offset ( @ $1000 on boot for debug purposes)
signal screen_ram_base : unsigned(27 downto 0) := x"0000400";
-- Pointer to the VIC-II compatibility sprite source vector, usually
-- screen+$3F8 in 40 column mode, or +$7F8 in VIC-III 80 column mode
signal vicii_sprite_pointer_address : unsigned(27 downto 0) := x"00013F8";
-- Character set address.
-- Size of character set depends on resolution of characters, and whether
-- full-colour characters are enabled.
signal character_set_address : unsigned(27 downto 0) := x"0000000";
signal character_data_from_rom : std_logic := '1';
-----------------------------------------------------------------------------
-- Character generator state. Also used for graphics modes, since graphics
-- modes on the C64 are all card-based, anyway.
signal card_number : unsigned(15 downto 0) := x"0000";
signal card_number_drive : unsigned(15 downto 0) := x"0000";
signal card_number_is_extended : std_logic; -- set if card_number > $00FF
signal first_card_of_row : unsigned(15 downto 0) := to_unsigned(0,15+1);
-- DEBUG: Set previous first card of row to all high so that a badline gets
-- triggered on the first raster being drawn.
-- Also used so that last pixel row in bitmap char cards doesn't show data
-- from the next char card down the screen.
signal prev_first_card_of_row : unsigned(15 downto 0) := (others => '1');
-- coordinates after applying the above scaling factors
signal chargen_x : unsigned(2 downto 0) := (others => '0');
signal chargen_y : unsigned(2 downto 0) := (others => '0');
signal chargen_y_next : unsigned(2 downto 0) := (others => '0');
signal chargen_y_hold : unsigned(2 downto 0) := (others => '0');
-- fractional pixel position for scaling
signal chargen_y_sub : unsigned(4 downto 0) := to_unsigned(0,4+1);
-- Allow double vertical resolution of chars in V200 mode
-- by multiplexing between normal and shifted charset
signal charrow_repeated : std_logic := '0';
signal reg_char_y16 : std_logic := '0';
-- Common bitmap and character drawing info
signal glyph_data_address : unsigned(19 downto 0) := to_unsigned(0,20);
-- For holding pre-calculated expressions to flatten logic
signal bitmap_glyph_data_address : unsigned(19 downto 0) := to_unsigned(0,20);
-- Bitmap drawing info
signal bitmap_colour_foreground : unsigned(7 downto 0) := x"00";
signal bitmap_colour_background : unsigned(7 downto 0) := x"00";
-- Character drawing info
signal background_colour_select : unsigned(1 downto 0) := "00";
signal glyph_number : unsigned(12 downto 0) := to_unsigned(0,13);
signal glyph_y_offset : integer range 0 to 7 := 0;
signal glyph_nve_y_offset : std_logic := '0';
signal glyph_colour_drive : unsigned(7 downto 0) := x"00";
signal glyph_colour_drive2 : unsigned(7 downto 0) := x"00";
signal glyph_colour : unsigned(7 downto 0) := x"00";
signal glyph_attributes : unsigned(3 downto 0) := "0000";
signal glyph_visible_drive : std_logic := '0';
signal glyph_visible : std_logic := '0';
signal glyph_bold : std_logic := '0';
signal glyph_bold_drive : std_logic := '0';
signal glyph_underline_drive : std_logic := '0';
signal glyph_underline : std_logic := '0';
signal glyph_reverse : std_logic := '0';
signal glyph_reverse_drive : std_logic := '0';
signal glyph_full_colour : std_logic := '0';
signal glyph_4bit : std_logic := '0';
signal glyph_flip_horizontal : std_logic := '0';
signal glyph_flip_vertical : std_logic := '0';
signal glyph_goto : std_logic := '0';
signal glyph_width_deduct : unsigned(3 downto 0) := to_unsigned(0,3+1);
signal glyph_width : integer range 0 to 16;
signal paint_glyph_width : integer range 0 to 16;
signal paint_glyph_4bit : std_logic := '0';
signal glyph_blink : std_logic := '0';
signal glyph_blink_drive : std_logic := '0';
signal paint_blink : std_logic := '0';
signal glyph_with_alpha : std_logic := '0';
signal paint_with_alpha : std_logic := '0';
signal glyph_trim_top : integer range 0 to 7;
signal glyph_trim_bottom : integer range 0 to 7;
signal glyph_paint_background : std_logic := '1';
signal glyph_alternate_palette_invert : std_logic := '0';
signal glyph_bold_and_reverse : std_logic := '0';
signal force_chars_foreground : std_logic := '1';
signal force_chars_background : std_logic := '0';
signal last_hyper_request_toggle : std_logic := '0';
signal short_line : std_logic := '0';
signal short_line_length : integer range 0 to 512;
signal screen_ram_is_ff : std_logic := '0';
signal screen_ram_high_is_ff : std_logic := '0';
signal row_advance : integer range 0 to 512;
signal card_of_row : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal chargen_active : std_logic := '0';
signal chargen_active_drive : std_logic := '0';
signal chargen_active_soon : std_logic := '0';
signal chargen_active_soon_drive : std_logic := '0';
-- Delayed versions of signals to allow character fetching pipeline
signal chargen_x_t1 : unsigned(2 downto 0) := (others => '0');
signal chargen_x_t2 : unsigned(2 downto 0) := (others => '0');
signal chargen_x_t3 : unsigned(2 downto 0) := (others => '0');
signal card_number_t1 : unsigned(7 downto 0) := (others => '0');
signal card_number_t2 : unsigned(7 downto 0) := (others => '0');
signal card_number_t3 : unsigned(7 downto 0) := (others => '0');
signal cards_differ : std_logic := '0';
signal indisplay_t1 : std_logic := '0';
signal indisplay_t2 : std_logic := '0';
signal indisplay_t3 : std_logic := '0';
signal cycles_to_next_card : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal cycles_to_next_card_drive : unsigned(7 downto 0) := to_unsigned(0,7+1);
-- Interface to character generator rom
signal charaddress : integer range 0 to 4095;
signal chardata : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal chardata_drive : unsigned(7 downto 0) := to_unsigned(0,7+1);
-- buffer of read data to improve timing
signal charrow : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal charrow_t1 : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
signal charrow_t2 : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(0,7+1));
-- C65 style 2K colour RAM
signal colourram_at_dc00_internal : std_logic := '0';
-- C65 ROM mapping
signal reg_rom_e000 : std_logic := '0';
signal reg_rom_c000 : std_logic := '0';
signal reg_rom_a000 : std_logic := '0';
signal reg_rom_8000 : std_logic := '0';
signal reg_c65_charset : std_logic := '0';
signal reg_palrom : std_logic := '0';
signal reg_h640 : std_logic := '0';
signal reg_h1280 : std_logic := '0';
signal reg_v400 : std_logic := '0';
signal reg_mono : std_logic := '0';
signal reg_interlace : std_logic := '0';
signal sprite_h640 : std_logic := '1';
signal sprite_v400s : std_logic_vector(7 downto 0) := x"00";
signal sprite_v400_msbs : std_logic_vector(7 downto 0) := x"00";
signal sprite_v400_super_msbs : std_logic_vector(7 downto 0) := x"00";
type rgb is
record
red : unsigned(7 downto 0);
green : unsigned(7 downto 0);
blue : unsigned(7 downto 0);
end record;
-- Border generation signals
-- (see video registers section for the registers that define the border size)
signal inborder : std_logic := '0';
signal pixel_alt_palette : std_logic := '0';
signal postsprite_inborder : std_logic := '0';
signal inborder_drive : std_logic := '0';
signal inborder_drive2 : std_logic := '0';
signal xfrontporch : std_logic := '0';
signal xfrontporch_drive : std_logic := '0';
signal xbackporch : std_logic := '0';
signal xbackporch_edge : std_logic := '0';
signal last_ramaddress : unsigned(19 downto 0) := to_unsigned(0,19+1);
signal ramaddress : unsigned(19 downto 0) := to_unsigned(0,19+1);
signal ramdata : unsigned(7 downto 0) := to_unsigned(0,7+1);
signal ramdata_drive : unsigned(7 downto 0) := to_unsigned(0,7+1);
-- Precalculated mono/multicolour pixel bits
signal multicolour_bits : std_logic_vector(1 downto 0) := (others => '0');
signal monobit : std_logic := '0';
-- Raster buffer
-- Read address is in 128th of pixels
signal raster_buffer_read_address : unsigned(10 downto 0) := to_unsigned(0,10+1);
signal raster_buffer_read_address_sub : unsigned(9 downto 0) := to_unsigned(0,9+1);
signal raster_buffer_read_address_next : unsigned(10 downto 0) := to_unsigned(0,10+1);
signal raster_buffer_read_address_sub_next : unsigned(9 downto 0) := to_unsigned(0,9+1);
signal raster_buffer_read_data : unsigned(17 downto 0) := to_unsigned(0,17+1);
signal raster_buffer_write_address : unsigned(10 downto 0) := to_unsigned(0,10+1);
signal raster_buffer_write_data : unsigned(17 downto 0) := to_unsigned(0,17+1);
signal raster_buffer_write : std_logic := '0';
signal raster_buffer_max_write_address : unsigned(9 downto 0) := to_unsigned(0,9+1);
signal raster_buffer_max_write_address_hold : unsigned(9 downto 0) := to_unsigned(0,9+1);
signal raster_buffer_max_write_address_prev : unsigned(9 downto 0) := to_unsigned(0,9+1);
signal no_raster_buffer_delay : std_logic := '1';
signal raster_buffer_double_line : std_logic := '0';
-- Colour RAM access for video controller
signal colourramaddress : unsigned(15 downto 0) := to_unsigned(0,15+1);
signal colourramdata : unsigned(7 downto 0) := to_unsigned(0,7+1);
-- ... and for CPU
signal colour_ram_fastio_address : unsigned(15 downto 0) := to_unsigned(0,15+1);
-- Palette RAM access via fastio port
signal palette_we : std_logic_vector(3 downto 0) := (others => '0');
signal palette_fastio_address : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(0,9+1));
signal palette_fastio_rdata : std_logic_vector(31 downto 0) := std_logic_vector(to_unsigned(0,31+1));
-- Palette RAM access for video controller
-- -- colour lookup for primary pixel pipeline
signal palette_address : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(0,9+1));
signal palette_rdata : std_logic_vector(31 downto 0) := std_logic_vector(to_unsigned(0,31+1));
-- -- colour lookup for anti-aliased font foreground colour
signal alias_palette_address : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(0,9+1));
signal alias_palette_rdata : std_logic_vector(31 downto 0) := std_logic_vector(to_unsigned(0,31+1));
-- -- colour lookup for alpha blending of visible sprite over
-- character generator
signal sprite_alias_palette_address : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(0,9+1));
signal sprite_alias_palette_rdata : std_logic_vector(31 downto 0) := std_logic_vector(to_unsigned(0,31+1));
-- Palette bank selection registers
signal palette_bank_fastio : std_logic_vector(1 downto 0) := "11";
signal palette_bank_chargen : std_logic_vector(1 downto 0) := "11";
signal palette_bank_chargen_alt : std_logic_vector(1 downto 0) := "11";
signal palette_bank_sprites : std_logic_vector(1 downto 0) := "11";
signal vsync_polarity_internal : std_logic := '0';
signal hsync_polarity_internal : std_logic := '0';
-- Mode line calculations
signal text_height_200 : integer := 0;
signal text_height_400 : integer := 0;
signal text_height : integer;
signal chargen_y_scale_200 : unsigned(7 downto 0) := (others => '0');
signal chargen_y_scale_400 : unsigned(7 downto 0) := (others => '0');
signal chargen_y_pixels : integer := 0;
-- Initialise the top border height to be > 6 to avoid boundary violations
-- during start up in simulation
signal top_borders_height_200 : unsigned(11 downto 0) := to_unsigned(16,12);
signal top_borders_height_400 : unsigned(11 downto 0) := to_unsigned(16,12);
signal single_top_border_200 : unsigned(11 downto 0) := to_unsigned(16,12);
signal single_top_border_400 : unsigned(11 downto 0) := to_unsigned(16,12);
signal viciv_flyback : std_logic := '0';
signal pixel_newframe_internal : std_logic := '0';
-- Signals for managing the state of the programmable screen RAM lists
-- We have a simple call-stack scheme, where GOTO tokens and GOSUB tokens
-- can cause redirection of the screen RAM stream being read. This happens
-- during the badline fetch, i.e., once per character row.
type screenline_return_stack_t is array (0 to 3) of unsigned(19 downto 0);
signal screenline_return_stack : screenline_return_stack_t;
signal screenline_return_stack_count : integer range 0 to 3 := 0;
-- We also allow shoving characters up or down, so that by displaying
-- a set of screen characters (possibly via a GOSUB token), they can be
-- displayed at any vertical offset, as well as horizontal offset via the
-- GOTOX tokens.
-- The draw_mask combined with the Y fine address offset mechanism allows
-- shifting a character up or down, and then masking off the parts that would
-- come from the previous or next character
signal screenline_draw_mask : unsigned(7 downto 0) := (others => '1');
signal screenline_draw_mask_drive : unsigned(7 downto 0) := (others => '1');
signal draw_mask_blank : std_logic := '0';
-- For accumulating the last token
signal screen_line_last_token : unsigned(15 downto 0) := x"0000";
-- Count down used to extracting read 16-bit character tokens from the
-- badline data stream (corrects for pipeline delay, and only every other
-- byte completing a 16-bit token).
signal badlineprog_countdown : integer := 0;
-- Count down used when branching in a badline program to flush the memory
-- fetch pipeline.
signal badlineprog_inhibit_screen_row_buffer_write_counter : integer := 0;
-- Indicates if the next 16 bit screen token will be a GOTO/GOSUB token
signal next_token_is_goto : std_logic := '0';
signal reg_alpha_delay : unsigned(3 downto 0) := x"1";
signal is_fetch_start : std_logic := '0';
signal last_was_fetch_start : std_logic := '0';
signal d031_writes : unsigned(7 downto 0) := x"00";
signal d031_written_internal : std_logic := '0';
signal badline_toggle_internal : std_logic := '0';
signal enable_raster_delay : std_logic := '1';
signal pixels_since_last_char : unsigned(2 downto 0) := "000";
signal render_activity : std_logic_vector(2 downto 0) := "000";
signal show_render_activity : std_logic := '0';
signal hyper_data : unsigned(7 downto 0) := x"00";
signal hyper_addr_drive : unsigned(18 downto 3) := x"0000";
signal hyper_data_strobe : std_logic := '0';
signal hyper_request_toggle_drive : std_logic := '0';
signal hyper_request_toggle_drive2 : std_logic := '0';
signal hyper_request_toggle_drive3 : std_logic := '0';
signal hyper_data_counter : unsigned(31 downto 0) := to_unsigned(0,32);
signal sprite_continuous_pointer_monitoring : std_logic := '1';
-- Set to 0 to disable bug compatibility D016 positioning
signal prev_hw_errata_level : unsigned(7 downto 0) := to_unsigned(0,8);
signal bug_compat_mode : std_logic := '1';
signal prev_bug_compat_mode : std_logic := '1';
signal bug_compat_vic_iii_d016_delta : integer := 2;
begin
rasterbuffer1: entity work.ram18x2k
port map (
clkl => pixelclock,
clkr => pixelclock,
wel(0) => raster_buffer_write,
dinl => std_logic_vector(raster_buffer_write_data),
unsigned(doutr) => raster_buffer_read_data,
addrl => std_logic_vector(raster_buffer_write_address(10 downto 0)),
addrr => std_logic_vector(raster_buffer_read_address_next)
);
buffer1: entity work.screen_ram_buffer
port map (
clka => pixelclock,
clkb => pixelclock,
dina => std_logic_vector(screen_ram_buffer_din),
unsigned(doutb) => screen_ram_buffer_dout,
wea(0) => screen_ram_buffer_write,
addra => std_logic_vector(screen_ram_buffer_write_address(9 downto 0)),
addrb => std_logic_vector(screen_ram_buffer_read_address(9 downto 0))
);
colourram: block
begin
colourram1 : entity work.ram8x32k
PORT MAP (
clka => cpuclock,
ena => colour_ram_cs,
wea(0) => fastio_write,
-- wea => fastio_write,
addra => std_logic_vector(colour_ram_fastio_address(14 downto 0)),
dina => fastio_wdata,
douta => colour_ram_fastio_rdata,
-- video controller use port b of the dual-port colour ram.
-- The CPU uses port a via the fastio interface
clkb => pixelclock,
web => (others => '0'),
-- web => '0',
addrb => std_logic_vector(colourramaddress(14 downto 0)),
dinb => (others => '0'),
unsigned(doutb) => colourramdata
);
end block;
-- Used for main pixel pipeline colour lookup
paletteram0: entity work.ram32x1024
port map (
clka => cpuclock,
ena => '1',
wea => palette_we,
addra => palette_fastio_address,
dina(31 downto 24) => fastio_wdata,
dina(23 downto 16) => fastio_wdata,
dina(15 downto 8) => fastio_wdata,
dina(7 downto 0) => fastio_wdata,
douta => palette_fastio_rdata,
clkb => pixelclock,
web => (others => '0'),
addrb => palette_address,
dinb => (others => '0'),
doutb => palette_rdata
);
-- Used for anti-aliased text colour lookup
paletteram1: entity work.ram32x1024
port map (
clka => cpuclock,
ena => '1',
wea => palette_we,
addra => palette_fastio_address,
dina(31 downto 24) => fastio_wdata,
dina(23 downto 16) => fastio_wdata,
dina(15 downto 8) => fastio_wdata,
dina(7 downto 0) => fastio_wdata,
-- douta => palette_fastio_rdata,
clkb => pixelclock,
web => (others => '0'),
addrb => alias_palette_address,
dinb => (others => '0'),
doutb => alias_palette_rdata
);
charrom1 : entity work.charrom
port map (Clk => pixelclock,
address => charaddress,
cs => '1', -- active
data_o => chardata,
cpuclk => cpuclock,
cpucs => charrom_cs,
cpuaddress => unsigned(fastio_addr(11 downto 0)),
we => fastio_write,
data_i => fastio_wdata,
cpu_data_o => charrom_fastio_rdata
);
compositeblender: entity work.alpha_blend_top
port map (clk1x => pixelclock,
reset => '0',
hsync_strm0 => '0',
vsync_strm0 => '0',
de_strm0 => '1',
-- RGB of background colour
r_strm1(9 downto 2) => std_logic_vector(composite_bg_red),
r_strm1(1 downto 0) => (others => '0'),
g_strm1(9 downto 2) => std_logic_vector(composite_bg_green),
g_strm1(1 downto 0) => (others => '0'),
b_strm1(9 downto 2) => std_logic_vector(composite_bg_blue),
b_strm1(1 downto 0) => (others => '0'),
de_strm1 => '1',
-- XXX: replace RGB and postsprite_pixel_colour values
-- with appropriately delayed signals
r_strm0(9 downto 2) => std_logic_vector(composite_red),
r_strm0(1 downto 0) => (others => '0'),
g_strm0(9 downto 2) => std_logic_vector(composite_green),
g_strm0(1 downto 0) => (others => '0'),
b_strm0(9 downto 2) => std_logic_vector(composite_blue),
b_strm0(1 downto 0) => (others => '0'),
de_alpha => '1',
alpha_strm(9 downto 2) => std_logic_vector(alpha_blend_alpha(7 downto 0)),
alpha_strm(1 downto 0) => "00",
alpha_delay => reg_alpha_delay,
r_blnd => composited_red,
g_blnd => composited_green,
b_blnd => composited_blue
);
pal_sim0: entity work.pal_simulation
port map(
clock => pixelclock,
shadow_mask_enable => shadow_mask_enable,
red_in => vga_palin_red,
green_in => vga_palin_green,
blue_in => vga_palin_blue,
red_out => vga_palout_red,
green_out => vga_palout_green,
blue_out => vga_palout_blue,
x_position => xcounter,
y_position => displayy
);
vicii_sprites0: entity work.vicii_sprites
port map (pixelclock => pixelclock,
cpuclock => cpuclock,
sprite_h640 => sprite_h640_delayed,
sprite_v400s => sprite_v400s_delayed,
bitplane_h640 => reg_h640_delayed,
bitplane_h1280 => reg_h1280_delayed,
bitplane_mode_in => bitplane_mode,
bitplane_enables_in => bitplane_enables,
bitplane_complements_in => bitplane_complements,
bitplanes_y_start => bitplanes_y_start_drive,
bitplanes_x_start => bitplanes_x_start_drive,
bitplane_sixteen_colour_mode_flags_in =>
bitplane_sixteen_colour_mode_flags,
sprite_datavalid_in => sprite_datavalid,
sprite_bytenumber_in => sprite_bytenumber,
sprite_spritenumber_in => sprite_spritenumber,
sprite_data_in => sprite_data_byte,
sprite_horizontal_tile_enables => sprite_horizontal_tile_enables,
sprite_bitplane_enables => sprite_bitplane_enables,
sprite_extended_width_enables => sprite_extended_width_enables,
sprite_extended_height_enables => sprite_extended_height_enables,
sprite_extended_height_size => sprite_extended_height_size,
sprite_sixteen_colour_enables => sprite_sixteen_colour_enables,
sprite_number_for_data_in => sprite_number_for_data_tx,
sprite_data_offset_out => sprite_data_offset_rx,
sprite_number_for_data_out => sprite_number_for_data_rx,
is_foreground_in => pixel_is_foreground_in,
is_background_in => pixel_is_background_in,
-- VIC-II sprites care only about VIC-II coordinates
-- XXX 40 and 80 column displays should have the same aspect
-- ratio for this to really work.
pipeline_delay => reg_xcounter_delay,
x320_in => to_xposition(vicii_xcounter_320),
x640_in => to_xposition(vicii_xcounter_640),
-- x1280 mode is deprecated
x1280_in => to_xposition(vicii_xcounter_640),
y_in => to_yposition(vicii_sprite_ycounter),
yfine_in => to_yposition(vicii_ycounter_v400),
border_in => inborder_drive2,
alt_palette_in => pixel_alt_palette,
pixel_in => chargen_pixel_colour,
alpha_in => chargen_alpha_value,
pixel_out => postsprite_pixel_colour,
alpha_out => postsprite_alpha_value,
border_out => postsprite_inborder,
alt_palette_out => postsprite_alternate_palette,
is_sprite_out => pixel_is_sprite,
sprite_number_out => postsprite_sprite_number,
is_background_out => pixel_is_background_out,
is_foreground_out => pixel_is_foreground_out,
-- Get sprite collision info
sprite_fg_map_final => vicii_sprite_bitmap_collision_map,
sprite_map_final => vicii_sprite_sprite_collision_map,
fastio_addr => fastio_addr,
fastio_write => fastio_write,
fastio_wdata => fastio_wdata
);
chipram_address <= next_ramaddress when safe_to_integer(next_ramaddress) < chipram_size else to_unsigned(0,20);
ramdata <= chipram_datain;
process(cpuclock,fastio_addr,fastio_read,chardata,
sprite_x,sprite_y,vicii_sprite_xmsbs,ycounter,extended_background_mode,
text_mode,blank,twentyfourlines,vicii_y_smoothscroll,displayy,
vicii_sprite_enables,multicolour_mode,thirtyeightcolumns,
vicii_x_smoothscroll,vicii_sprite_y_expand,screen_ram_base,
character_set_address,irq_collisionspritebitmap,irq_collisionspritesprite,
irq_raster,mask_collisionspritebitmap,mask_collisionspritesprite,
mask_raster,vicii_sprite_priority_bits,vicii_sprite_multicolour_bits,
vicii_sprite_sprite_collisions,vicii_sprite_bitmap_collisions,
border_colour,screen_colour,multi1_colour,multi2_colour,multi3_colour,
border_x_left,border_x_right,border_y_top,border_y_bottom,
x_chargen_start,y_chargen_start,fullcolour_8bitchars,
fullcolour_extendedchars,sixteenbit_charset,
cycles_to_next_card,xfrontporch,xbackporch,chargen_active,inborder,
irq_drive,vicii_sprite_x_expand,sprite_multi0_colour,
sprite_multi1_colour,sprite_colours,colourram_at_dc00_internal,
viciii_extended_attributes,virtual_row_width,chargen_x_scale,
chargen_y_scale,xcounter,chargen_active_soon,card_number,
colour_ram_base,vicii_sprite_pointer_address,palette_bank_fastio,
debug_cycles_to_next_card,
debug_chargen_active,debug_raster_fetch_state,debug_charaddress,
debug_charrow,palette_fastio_rdata,palette_bank_chargen,
debug_chargen_active_soon,palette_bank_sprites,
vicii_ycounter,reg_rom_e000,reg_rom_c000,
reg_rom_a000,reg_c65_charset,reg_rom_8000,reg_palrom,
reg_h640,reg_h1280,reg_v400,reg_interlace,xcounter_drive,ycounter_drive,
horizontal_filter,xfrontporch_drive,chargen_active_drive,
chargen_active_soon_drive,card_number_drive,
bitplanes_x_start,bitplanes_y_start,dat_y,dat_x,dat_bitplane_offset,
bitplane_addresses,vicii_2mhz_internal,viciii_fast_internal,
bitplane_mode,bitplane_enables,bitplane_addresses,bitplane_complements,
sprite_bitplane_enables,sprite_horizontal_tile_enables,compositer_enable,
viciv_fast_internal,pal_simulate,sprite_extended_height_enables,
sprite_extended_height_size,sprite_extended_width_enables,
chargen_x_scale_drive,single_side_border,
sprite_first_x,sprite_sixteen_colour_enables,
vicii_ntsc,vicii_first_raster,
palette_bank_chargen_alt,bitplane_sixteen_colour_mode_flags,
vicii_ycounter_scale_minus_zero,
hsync_polarity_internal,vsync_polarity_internal,
vicii_ycounter_minus_one,lightpen_x_latch,lightpen_y_latch,irq_rasterx,irq_lightpen,
mask_rasterx,mask_lightpen,no_raster_buffer_delay,raster_buffer_double_line,
vicii_is_raster_source,shadow_mask_enable,sprite_h640,vicii_hot_regs_enable,
display_row_width,sprite_h640_msbs,glyphs_from_hyperram,fullcolour_mcm,
reg_xcounter_delay,show_render_activity,test_pattern_enable,vga60_select_internal,
sprite_y_adjust,reg_alpha_delay,sprite_alpha_blend_value,sprite_alpha_blend_enables,
sprite_v400s,sprite_v400_msbs,sprite_v400_super_msbs,vicii_raster_compare,
sprite_continuous_pointer_monitoring,display_row_count,bitplane_bank_select,
hypervisor_mode,debug_channel_select,hyper_data_counter,debug_pixel_red,
debug_pixel_green,debug_pixel_blue,debug_x,debug_y,bug_compat_mode,
reg_mono,upscale_enable_int,enable_raster_delay,reg_char_y16
) is
variable bitplane_number : integer;
procedure viciv_calculate_modeline_dimensions is
constant w : integer := 400; -- was 320
begin
-- Display is a fixed 600 pixels high, so set Y scaling appropriately
chargen_y_scale_200 <= to_unsigned(2,8);
chargen_y_scale_400 <= to_unsigned(1,8);
text_height_200 <= 400;
text_height_400 <= 400;
-- Calculate height of top borders
top_borders_height_200 <= to_unsigned(safe_to_integer(display_height)
- text_height_200,12);
single_top_border_200(10 downto 0) <= top_borders_height_200(11 downto 1);
single_top_border_200(11) <= '0';
top_borders_height_400 <= to_unsigned(safe_to_integer(display_height)
- text_height_400,12);
single_top_border_400(10 downto 0) <= top_borders_height_400(11 downto 1);
single_top_border_400(11) <= '0';
end procedure;
procedure viciv_interpret_legacy_mode_registers is
begin
-- set x_chargen
report "LEGACY register update";
if reg_h640='0' then
x_chargen_start
<= to_unsigned(safe_to_integer(frame_h_front)
+safe_to_integer(single_side_border)
-- VIC-II smooth scrolling is based on H320/400 and real
-- pixels are H640/800, so add double
+safe_to_integer(vicii_x_smoothscroll)
+safe_to_integer(vicii_x_smoothscroll)
,14);
else
x_chargen_start
<= to_unsigned(safe_to_integer(frame_h_front)
+safe_to_integer(single_side_border)
-- VIC-II smooth scrolling is based on H320/400 and real
-- pixels are H640/800, so add double
+safe_to_integer(vicii_x_smoothscroll)
+safe_to_integer(vicii_x_smoothscroll)
-bug_compat_vic_iii_d016_delta
,14);
end if;
if reg_h640='0' then
-- 40 column mode
virtual_row_width <= to_unsigned(40,16);
display_row_width <= to_unsigned(40,10);
elsif reg_h640='1' then
-- 80 column mode
virtual_row_width <= to_unsigned(80,16);
display_row_width <= to_unsigned(80,10);
end if;
if reg_v400='0' then
display_row_count <= to_unsigned(25-1,8);
chargen_y_scale <= to_unsigned(safe_to_integer(chargen_y_scale_200)-1,8);
-- set vertical borders based on twentyfourlines
if twentyfourlines='0' then
border_y_top <= to_unsigned(
raster_correction+
safe_to_integer(single_top_border_200)-safe_to_integer(vicii_first_raster)*2,12);
border_y_bottom <= to_unsigned(
raster_correction+
safe_to_integer(single_top_border_200)-safe_to_integer(vicii_first_raster)*2+
text_height_200,12);
else
border_y_top <= to_unsigned(raster_correction
+safe_to_integer(single_top_border_200)
-safe_to_integer(vicii_first_raster)*2
+(4*2),12);
border_y_bottom <= to_unsigned(raster_correction
+safe_to_integer(single_top_border_200)
-safe_to_integer(vicii_first_raster)*2
+text_height_200
-(4*2),12);
end if;
-- set y_chargen_start based on twentyfourlines
report "XXX vicii_y_smoothscroll = " & to_string(std_logic_vector(vicii_y_smoothscroll));
report "XXX raster_correction = " & integer'image(raster_correction);
report "XXX single_top_border_200 = " & integer'image(safe_to_integer(single_top_border_200));
report "XXX vicii_first_raster = " & integer'image(safe_to_integer(vicii_first_raster));
y_chargen_start <= unsigned(to_signed(raster_correction
+safe_to_integer(single_top_border_200)
-safe_to_integer(vicii_first_raster)*2
-(3*2)
-- Display is always V400/600, so pixels
-- are double height
+safe_to_integer(vicii_y_smoothscroll)
+safe_to_integer(vicii_y_smoothscroll)
,12));
else
-- V400 mode : as above, but with the different constants
display_row_count <= to_unsigned(50-1,8);
chargen_y_scale <= to_unsigned(safe_to_integer(chargen_y_scale_400)-1,8);
-- set vertical borders based on twentyfourlines
if twentyfourlines='0' then
border_y_top <= to_unsigned(
raster_correction+
safe_to_integer(single_top_border_400)
-safe_to_integer(vicii_first_raster)*2,12);
border_y_bottom <= to_unsigned(
raster_correction+
safe_to_integer(single_top_border_400)-safe_to_integer(vicii_first_raster)*2+
text_height_400,12);
else
border_y_top <= to_unsigned(raster_correction
+safe_to_integer(single_top_border_400)
-safe_to_integer(vicii_first_raster)*2
+(4*2),12);
border_y_bottom <= to_unsigned(raster_correction
+safe_to_integer(single_top_border_400)
-safe_to_integer(vicii_first_raster)*2
+text_height_400
-(4*2),12);
end if;
-- set y_chargen_start based on twentyfourlines
y_chargen_start <= to_unsigned(raster_correction
+safe_to_integer(single_top_border_400)
-safe_to_integer(vicii_first_raster)*2
-(3*2)
-- Screen is always V400/600, so pixels
-- are 2 physical pixels high
+safe_to_integer(vicii_y_smoothscroll)
+safe_to_integer(vicii_y_smoothscroll)
,12);
end if;
screen_ram_base(27 downto 16) <= (others => '0');
if reg_h640='1' then
screen_ram_base(13 downto 11) <= reg_d018_screen_addr(3 downto 1);
screen_ram_base(10 downto 0) <= (others => '0');
else
screen_ram_base(13 downto 10) <= reg_d018_screen_addr;
screen_ram_base(9 downto 0) <= (others => '0');
end if;
-- Sprites fetch from screen ram base + $3F8 (or +$7F8 in VIC-III 80
-- column mode).
-- In 80 column mode the screen base must be on a 2K boundary on the
-- C65, which changes the interpretation of the screen_ram_base.
-- Note that our interpretation of V400 to double the number of text
-- rows breaks strict C65 compatibility.
vicii_sprite_pointer_address(27 downto 16) <= (others => '0');
-- NOTE: Bits 14 and 15 are still set only by writing to $DD00
-- or the VIC-IV registers that modify this.
vicii_sprite_pointer_address(13 downto 10)
<= reg_d018_screen_addr;
if reg_h640='1' or reg_v400='1' then
vicii_sprite_pointer_address(10) <= '1';
end if;
vicii_sprite_pointer_address(9 downto 0) <= "1111111000";
-- Apply VIC-II banks
screen_ram_base(15 downto 14) <= not last_dd00_bits;
vicii_sprite_pointer_address(15 downto 14) <= not last_dd00_bits;
character_set_address(15 downto 14) <= not last_dd00_bits;
-- NOTE: We DONT reset the character set address with a legacy write,
-- even if HOTREG are enabled. This makes it easier to use alternate
-- character sets, and full-colour text mode upgrading of old programmes.
-- All VIC-II/VIC-III compatibility modes use the first part of the
-- colour RAM.
colour_ram_base <= (others => '0');
-- NOTE: We DONT reset the character set address with a legacy write.
-- This makes it easier to use alternate character sets, and full-colour
-- text mode upgrading of old programmes.
end procedure viciv_interpret_legacy_mode_registers;
procedure viciv_update_side_border_dimensions is
begin
-- set horizontal borders based on 40/38 columns
report "LEGACY register update";
if thirtyeightcolumns='0' then
if reg_h640='0' then
border_x_left <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(single_side_border),14);
border_x_right <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(display_width)
-safe_to_integer(single_side_border),14);
else
border_x_left <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(single_side_border),14);
border_x_right <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(display_width)
-safe_to_integer(single_side_border),14);
end if;
else
if reg_h640='0' then
border_x_left <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(single_side_border)
+(7*2),14);
border_x_right <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(display_width)
-safe_to_integer(single_side_border)
-(9*2),14);
else
border_x_left <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(single_side_border)
+(7*2),14);
border_x_right <= to_unsigned(safe_to_integer(frame_h_front)+safe_to_integer(display_width)
-safe_to_integer(single_side_border)
-(9*2),14);
end if;
end if;
end procedure viciv_update_side_border_dimensions;
variable register_bank : unsigned(7 downto 0) := to_unsigned(0,7+1);
variable register_page : unsigned(3 downto 0) := to_unsigned(0,3+1);
variable register_num : unsigned(7 downto 0) := to_unsigned(0,7+1);
variable register_number : unsigned(11 downto 0) := to_unsigned(0,11+1);
begin
fastio_rdata <= (others => 'Z');
chargen_x_scale_drive <= chargen_x_scale;
bitplanes_x_start_drive <= bitplanes_x_start;
bitplanes_y_start_drive <= bitplanes_y_start;
-- Calculate DAT bitplane offset
-- XXX currently ignores V400 mode
if reg_v400 = '0' or reg_interlace = '0' then
if reg_h640 = '0' then
dat_bitplane_offset <=
("00" & dat_y(8 downto 3) & "00000000")
+ ("0000" & dat_y(8 downto 3) & "000000")
+ ("0000000000000" & dat_y(2 downto 0))
+ ("000000" & dat_x & "000");
else
dat_bitplane_offset <=
("0" & dat_y(8 downto 3) & "000000000")
+ ("000" & dat_y(8 downto 3) & "0000000")
+ ("0000000000000" & dat_y(2 downto 0))
+ ("000000" & dat_x & "000");
end if;
dat_even <= '1';
else
-- For V400 + Interlace, we need to pick even/odd frame
-- This must mean that the bottom bit of dat_y indicates
-- the odd/even frame, and all the other bits of dat_y are
-- shifted right a bit to exclude it.
if reg_h640 = '0' then
dat_bitplane_offset <=
("000" & dat_y(8 downto 4) & "00000000")
+ ("0000" & dat_y(8 downto 3) & "000000")
+ ("0000000000000" & dat_y(3 downto 1))
+ ("000000" & dat_x & "000");
else
dat_bitplane_offset <=
("00" & dat_y(8 downto 4) & "000000000")
+ ("000" & dat_y(8 downto 3) & "0000000")
+ ("0000000000000" & dat_y(3 downto 1))
+ ("000000" & dat_x & "000");
end if;
dat_even <= not dat_y(0);
end if;
-- Export this and bitplane addresses to the CPU
dat_offset <= dat_bitplane_offset;
dat_bitplane_addresses <= bitplane_addresses;
if true then
-- Calculate register number asynchronously
register_number := x"FFF";
if fastio_addr(19) = '0' or fastio_addr(19) = '1' then
register_bank := unsigned(fastio_addr(19 downto 12));
register_page := unsigned(fastio_addr(11 downto 8));
register_num := unsigned(fastio_addr(7 downto 0));
else
-- Give values when inputs are bad to supress warnings cluttering output
-- when simulating
register_bank := x"FF";
register_page := x"F";
register_num := x"FF";
end if;
if register_bank=x"D0" and register_page<4 then
-- First 1KB of normal C64 IO space maps to r$0 - r$3F
register_number(5 downto 0) := unsigned(fastio_addr(5 downto 0));
register_number(11 downto 6) := (others => '0');
if fastio_addr(11 downto 0) = x"030" then
-- C128 $D030
register_number := x"0FF"; -- = 255
elsif (fastio_addr(11 downto 4) = x"03")
or (fastio_addr(11 downto 4) = x"07")
then
-- $D030-$D03F are otherwise unmapped in VIC-II mode, so that the C65
-- VIC-III registers there cannot be messed with.
-- So we set it to a non-existent register
-- We also have to do the same for $D070-$D07F
register_number := x"0FE";
end if;
report "IO access resolves to video register number "
& integer'image(safe_to_integer(register_number)) severity note;
elsif (register_bank = x"D1" or register_bank = x"D2"or register_bank = x"D3") and register_page<4 then
register_number(11 downto 10) := "00";
register_number(9 downto 8) := register_page(1 downto 0);
register_number(7 downto 0) := register_num;
report "IO access resolves to video register number "
& integer'image(safe_to_integer(register_number)) severity note;
end if;
-- $D800 - $DBFF colour RAM access.
-- This is a bit fun, because colour RAM is mapped in 3 separate places:
-- $D800 - $DBFF in the usual IO pages.
-- $DC00 - $DFFF in the enhanced IO pages when the correct VIC-III
-- register is set.
-- $FF80000-$FF8FFFF - All 64KB of colour RAM
-- The colour RAM has to be dual-port since the video controller needs to
-- access it as well, so all these have to be mapped on a single port.
colour_ram_fastio_address <= (others => '1');
if register_bank = x"D0" or register_bank = x"D1"
or register_bank = x"D2" or register_Bank=x"D3" then
if register_page>=8 and register_page<12 then
-- colour ram read $D800 - $DBFF
colour_ram_fastio_address <= unsigned("000000" & fastio_addr(9 downto 0));
elsif register_page>=12 and register_page<=15 then
-- colour ram read $DC00 - $DFFF
colour_ram_fastio_address <= unsigned("000001" & fastio_addr(9 downto 0));
else
colour_ram_fastio_address <= (others => '0');
end if;
elsif register_bank(7 downto 4)=x"8" then
-- colour RAM all 64KB
colour_ram_fastio_address <= unsigned(fastio_addr(15 downto 0));
end if;
if fastio_read='0' then
fastio_rdata <= (others => 'Z');
else
-- report "read from fastio detect in video controller. " &
-- "register number = " & integer'image(safe_to_integer(register_number)) &
-- ", fastio_addr = " & to_hstring(fastio_addr) &
-- ", register_bank = " & to_hstring(register_bank) &
-- ", register_page = " & to_hstring(register_page)
-- severity note;
if register_number>=0 and register_number<8 then
-- compatibility sprite coordinates
fastio_rdata <= std_logic_vector(sprite_x(safe_to_integer(register_num(2 downto 0))));
elsif register_number<16 then
-- compatibility sprite coordinates
fastio_rdata <= std_logic_vector(sprite_y(safe_to_integer(register_num(2 downto 0))));
elsif register_number=16 then
-- compatibility sprite x position MSB
fastio_rdata <= vicii_sprite_xmsbs;
elsif register_number=17 then -- $D011
fastio_rdata(7) <= vicii_ycounter_minus_one(8); -- MSB of raster
fastio_rdata(6) <= extended_background_mode;
fastio_rdata(5) <= not text_mode;
fastio_rdata(4) <= not blank;
fastio_rdata(3) <= not twentyfourlines;
fastio_rdata(2 downto 0) <= std_logic_vector(vicii_y_smoothscroll);
elsif register_number=18 then -- $D012 current raster low 8 bits
fastio_rdata <= std_logic_vector(vicii_ycounter_minus_one(7 downto 0));
elsif register_number=19 then -- $D013 lightpen X (coarse rasterX)
fastio_rdata <= std_logic_vector(lightpen_x_latch);
elsif register_number=20 then -- $D014 lightpen Y (coarse rasterY)
fastio_rdata <= std_logic_vector(lightpen_y_latch);
elsif register_number=21 then -- $D015 compatibility sprite enable
fastio_rdata <= vicii_sprite_enables;
elsif register_number=22 then -- $D016
fastio_rdata(7) <= '1';
fastio_rdata(6) <= '1';
fastio_rdata(5) <= '0'; -- no reset support, since no badlines
fastio_rdata(4) <= multicolour_mode;
fastio_rdata(3) <= not thirtyeightcolumns;
fastio_rdata(2 downto 0) <= std_logic_vector(vicii_x_smoothscroll);
elsif register_number=23 then -- $D017 compatibility sprite Y
-- expand enable
fastio_rdata <= vicii_sprite_y_expand;
elsif register_number=24 then -- $D018 compatibility RAM addresses
fastio_rdata <=
std_logic_vector(screen_ram_base(13 downto 10))
& std_logic_vector(character_set_address(13 downto 10));
elsif register_number=25 then -- $D019 compatibility IRQ bits
fastio_rdata(7) <= not irq_drive;
fastio_rdata(6) <= '1'; -- NC
fastio_rdata(5) <= '1'; -- NC
fastio_rdata(4) <= irq_rasterx;
fastio_rdata(3) <= irq_lightpen;
fastio_rdata(2) <= irq_collisionspritesprite;
fastio_rdata(1) <= irq_collisionspritebitmap;
fastio_rdata(0) <= irq_raster;
elsif register_number=26 then -- $D01A compatibility IRQ mask bits
fastio_rdata(7) <= '1'; -- NC
fastio_rdata(6) <= '1'; -- NC
fastio_rdata(5) <= '1'; -- NC
fastio_rdata(4) <= mask_rasterx;
fastio_rdata(3) <= mask_lightpen;
fastio_rdata(2) <= mask_collisionspritesprite;
fastio_rdata(1) <= mask_collisionspritebitmap;
fastio_rdata(0) <= mask_raster;
elsif register_number=27 then -- $D01B sprite background priority
fastio_rdata <= vicii_sprite_priority_bits;
elsif register_number=28 then -- $D01C sprite multicolour
fastio_rdata <= vicii_sprite_multicolour_bits;
elsif register_number=29 then -- $D01D compatibility sprite enable
fastio_rdata <= vicii_sprite_x_expand;
elsif register_number=30 then -- $D01E sprite/sprite collissions
fastio_rdata <= vicii_sprite_sprite_collisions;
elsif register_number=31 then -- $D01F sprite/foreground collissions
fastio_rdata <= vicii_sprite_bitmap_collisions;
elsif register_number=32 then
fastio_rdata <= std_logic_vector(border_colour);
elsif register_number=33 then
-- Match C64's VIC-II behaviour of showing only the lower 4 bits of
-- screen colour, with the upper four bits = $F when in VIC-II IO context
fastio_rdata(3 downto 0) <= std_logic_vector(screen_colour(3 downto 0));
if register_bank /= x"D0" then
fastio_rdata(7 downto 4) <= std_logic_vector(screen_colour(7 downto 4));
else
fastio_rdata(7 downto 4) <= x"f";
end if;
elsif register_number=34 then
fastio_rdata <= std_logic_vector(multi1_colour);
elsif register_number=35 then
fastio_rdata <= std_logic_vector(multi2_colour);
elsif register_number=36 then
fastio_rdata <= std_logic_vector(multi3_colour);
elsif register_number=37 then
fastio_rdata <= std_logic_vector(sprite_multi0_colour);
elsif register_number=38 then
fastio_rdata <= std_logic_vector(sprite_multi1_colour);
elsif register_number>=39 and register_number<=46 then
fastio_rdata <= std_logic_vector(sprite_colours(safe_to_integer(register_number)-39));
elsif register_number=255 then
-- C128 $D030 emulation (2MHz mode only)
fastio_rdata(7 downto 1) <= (others => '0');
fastio_rdata(0) <= vicii_2mhz_internal;
elsif register_number=48 then
-- C65 $D030 emulation
fastio_rdata <=
reg_rom_e000 -- ROM @ E000
& reg_c65_charset -- character set select (D000 vs 9000)
& reg_rom_c000 -- ROM @ C000
& reg_rom_a000 -- ROM @ A000
& reg_rom_8000 -- ROM @ 8000
& reg_palrom -- First sixteen palette entries are fixed
-- (fetch from palette bank 3 on VIC-IV)
& "0" -- External sync
& colourram_at_dc00_internal; -- 2KB colour RAM
elsif register_number=49 then
-- Can emulate VIC-III H640, V400 and H1280 by adjusting x and y scale
-- registers
fastio_rdata <=
reg_h640 -- H640
& viciii_fast_internal -- FAST
& viciii_extended_attributes -- ATTR (8bit colour RAM features)
& bitplane_mode -- BPM
& reg_v400 -- V400
& reg_h1280 -- H1280
& reg_mono -- Mono mode for composite output
& reg_interlace; -- INT(erlaced?)
-- Skip $D02F - $D03F to avoid real C65/C128 programs trying to
-- fiddle with registers in this range.
-- For more C65 register info, see:
-- http://www.zimmers.net/cbmpics/cbm/c65/c65manual.txt
-- @IO:C65 $D032 VIC-III:BPENABLE Bitplane enable bits
elsif register_number=50 then
fastio_rdata <= bitplane_enables;
-- @IO:C65 $D033 - Bitplane 0 address
-- @IO:C65 $D034 - Bitplane 1 address
-- @IO:C65 $D035 - Bitplane 2 address
-- @IO:C65 $D036 - Bitplane 3 address
-- @IO:C65 $D037 - Bitplane 4 address
-- @IO:C65 $D038 - Bitplane 5 address
-- @IO:C65 $D039 - Bitplane 6 address
-- @IO:C65 $D03A - Bitplane 7 address
elsif register_number >= 51 and register_number <= 58 then
-- @IO:C65 $D033-$D03A - VIC-III Bitplane addresses
bitplane_number := safe_to_integer(register_number(3 downto 0)) - 3;
fastio_rdata <= std_logic_vector(bitplane_addresses(bitplane_number));
-- @IO:C65 $D03B - Set bits to NOT bitplane contents
elsif register_number=59 then
fastio_rdata <= bitplane_complements;
-- @IO:C65 $D03C - Bitplane X
elsif register_number=60 then
fastio_rdata(6 downto 0) <= std_logic_vector(dat_x(6 downto 0));
fastio_rdata(7) <= dat_y(8);
-- @IO:C65 $D03D - Bitplane Y
elsif register_number=61 then
fastio_rdata <= std_logic_vector(dat_y(7 downto 0));
-- @IO:C65 $D03E - Horizontal position (screen verniers?)
elsif register_number=62 then
fastio_rdata <= std_logic_vector(bitplanes_x_start);
-- @IO:C65 $D03F - Vertical position (screen verniers?)
elsif register_number=63 then
fastio_rdata <= std_logic_vector(bitplanes_y_start);
-- $D040 - $D047 DAT memory ports for bitplanes 0 through 7
-- XXX: Deprecated old addresses for some VIC-IV features currently occupy
-- these addresses
elsif register_number=64 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=65 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=66 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=67 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=68 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=69 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=70 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=71 then
-- Unimplemented VIC-III DAC
fastio_rdata <= x"FF";
elsif register_number=72 then
fastio_rdata <= std_logic_vector(border_y_top(7 downto 0));
elsif register_number=73 then
fastio_rdata(7 downto 4) <= sprite_bitplane_enables(3 downto 0);
fastio_rdata(3 downto 0) <= std_logic_vector(border_y_top(11 downto 8));
elsif register_number=74 then
fastio_rdata <= std_logic_vector(border_y_bottom(7 downto 0));
elsif register_number=75 then
fastio_rdata(7 downto 4) <= sprite_bitplane_enables(7 downto 4);
fastio_rdata(3 downto 0) <= std_logic_vector(border_y_bottom(11 downto 8));
elsif register_number=76 then
fastio_rdata <= std_logic_vector(x_chargen_start(7 downto 0));
elsif register_number=77 then
fastio_rdata(7 downto 4) <= sprite_horizontal_tile_enables(3 downto 0);
fastio_rdata(3 downto 0) <= std_logic_vector(x_chargen_start(11 downto 8));
elsif register_number=78 then
fastio_rdata <= std_logic_vector(y_chargen_start(7 downto 0));
elsif register_number=79 then
fastio_rdata(7 downto 4) <= sprite_horizontal_tile_enables(7 downto 4);
fastio_rdata(3 downto 0) <= std_logic_vector(y_chargen_start(11 downto 8));
elsif register_number=80 then
fastio_rdata <= std_logic_vector(xcounter_drive(7 downto 0));
elsif register_number=81 then
fastio_rdata(7) <= no_raster_buffer_delay;
fastio_rdata(6) <= raster_buffer_double_line;
fastio_rdata(5 downto 0) <= std_logic_vector(xcounter_drive(13 downto 8));
elsif register_number=82 then
-- Read physical raster LSB
fastio_rdata <= std_logic_vector(ycounter_drive(7 downto 0));
elsif register_number=83 then
-- Read physical raster MSB and raster compare source flag
fastio_rdata(7) <= vicii_is_raster_source;
fastio_rdata(6) <= shadow_mask_enable;
fastio_rdata(5) <= upscale_enable_int;
fastio_rdata(4) <= '0';
fastio_rdata(3 downto 0) <= std_logic_vector(ycounter_drive(11 downto 8));
elsif register_number=84 then
-- $D054 (53332) - New mode control register
fastio_rdata(7) <= compositer_enable;
fastio_rdata(6) <= viciv_fast_internal;
fastio_rdata(5) <= pal_simulate;
fastio_rdata(4) <= sprite_h640;
fastio_rdata(3) <= horizontal_filter;
fastio_rdata(2) <= fullcolour_extendedchars;
fastio_rdata(1) <= fullcolour_8bitchars;
fastio_rdata(0) <= sixteenbit_charset;
elsif register_number=85 then
fastio_rdata <= sprite_extended_height_enables;
elsif register_number=86 then
fastio_rdata <= std_logic_vector(sprite_extended_height_size);
elsif register_number=87 then
fastio_rdata <= sprite_extended_width_enables;
elsif register_number=88 then
fastio_rdata <= std_logic_vector(virtual_row_width(7 downto 0));
elsif register_number=89 then
fastio_rdata <= std_logic_vector(virtual_row_width(15 downto 8));
elsif register_number=90 then
fastio_rdata <= std_logic_vector(chargen_x_scale_drive);
elsif register_number=91 then
fastio_rdata <= std_logic_vector(chargen_y_scale);
elsif register_number=92 then
fastio_rdata <= std_logic_vector(single_side_border(7 downto 0));
elsif register_number=93 then
fastio_rdata(7) <= vicii_hot_regs_enable;
fastio_rdata(6) <= enable_raster_delay;
fastio_rdata(5 downto 0) <= std_logic_vector(single_side_border(13 downto 8));
elsif register_number=94 then
fastio_rdata(7 downto 0) <= std_logic_vector(display_row_width(7 downto 0));
elsif register_number=95 then
fastio_rdata <= std_logic_vector(sprite_h640_msbs);
elsif register_number=96 then
fastio_rdata <= std_logic_vector(screen_ram_base(7 downto 0));
elsif register_number=97 then
fastio_rdata <= std_logic_vector(screen_ram_base(15 downto 8));
elsif register_number=98 then
fastio_rdata <= std_logic_vector(screen_ram_base(23 downto 16));
elsif register_number=99 then
fastio_rdata(7) <= glyphs_from_hyperram;
fastio_rdata(6) <= fullcolour_mcm;
fastio_rdata(5 downto 4) <= std_logic_vector(display_row_width(9 downto 8));
fastio_rdata(3 downto 0) <= std_logic_vector(screen_ram_base(27 downto 24));
elsif register_number=100 then
fastio_rdata <= std_logic_vector(colour_ram_base(7 downto 0));
elsif register_number=101 then
fastio_rdata <= std_logic_vector(colour_ram_base(15 downto 8));
elsif register_number=102 then -- $D3066 xcounter_pipeline_delayed delay
fastio_rdata(5 downto 0) <= std_logic_vector(to_unsigned(reg_xcounter_delay,6));
fastio_rdata(6) <= show_render_activity;
fastio_rdata(7) <= test_pattern_enable;
elsif register_number=103 then -- $D3067
fastio_rdata <= std_logic_vector(sprite_first_x(7 downto 0));
elsif register_number=104 then -- $D068
fastio_rdata <= std_logic_vector(character_set_address(7 downto 0));
elsif register_number=105 then
fastio_rdata <= std_logic_vector(character_set_address(15 downto 8));
elsif register_number=106 then
fastio_rdata <= std_logic_vector(character_set_address(23 downto 16));
elsif register_number=107 then
fastio_rdata <= std_logic_vector(sprite_sixteen_colour_enables);
elsif register_number=108 then
fastio_rdata <= std_logic_vector(vicii_sprite_pointer_address(7 downto 0));
elsif register_number=109 then
fastio_rdata <= std_logic_vector(vicii_sprite_pointer_address(15 downto 8));
elsif register_number=110 then
fastio_rdata <= std_logic_vector(vicii_sprite_pointer_address(23 downto 16));
elsif register_number=111 then
fastio_rdata(7) <= vicii_ntsc;
fastio_rdata(6) <= vga60_select_internal;
fastio_rdata(5 downto 0) <= std_logic_vector(vicii_first_raster(5 downto 0));
elsif register_number=112 then -- $D3070
fastio_rdata <= palette_bank_fastio & palette_bank_chargen & palette_bank_sprites & palette_bank_chargen_alt;
elsif register_number=113 then -- $D3071
fastio_rdata <= bitplane_sixteen_colour_mode_flags;
elsif register_number=114 then -- $D3072
fastio_rdata(7 downto 0) <= std_logic_vector(sprite_y_adjust);
elsif register_number=115 then -- $D3073
fastio_rdata(3 downto 0) <= std_logic_vector(reg_alpha_delay);
fastio_rdata(7 downto 4) <= std_logic_vector(vicii_ycounter_scale_minus_zero(3 downto 0));
elsif register_number=116 then -- $D3074
fastio_rdata <= sprite_alpha_blend_enables;
elsif register_number=117 then -- $D3075
fastio_rdata(7 downto 0) <= std_logic_vector(sprite_alpha_blend_value);
elsif register_number=118 then -- $D3076 Sprite V400 enables
fastio_rdata <= std_logic_vector(sprite_v400s);
elsif register_number=119 then -- $D3077 Sprite V400 Y position MSBs
fastio_rdata <= sprite_v400_msbs;
elsif register_number=120 then -- $D3078 Sprite V400 Y position super MSBs
fastio_rdata <= sprite_v400_super_msbs;
elsif register_number=121 then -- $D3079 Read raster compare LSB
fastio_rdata <= std_logic_vector(vicii_raster_compare(7 downto 0));
elsif register_number=122 then -- $D307A Read raster compare MSB / raster compare source
fastio_rdata(2 downto 0) <= std_logic_vector(vicii_raster_compare(10 downto 8));
fastio_rdata(3) <= sprite_continuous_pointer_monitoring;
fastio_rdata(4) <= reg_char_y16;
fastio_rdata(5) <= not bug_compat_mode;
fastio_rdata(6) <= '0';
fastio_rdata(7) <= vicii_is_raster_source;
elsif register_number=123 then -- $D307B
fastio_rdata <= std_logic_vector(display_row_count(7 downto 0));
elsif register_number=124 then -- $D307C
-- fastio_rdata(3 downto 0) <= x"F";
fastio_rdata(2 downto 0) <= std_logic_vector(bitplane_bank_select);
fastio_rdata(3) <= '0';
fastio_rdata(4) <= hsync_polarity_internal;
fastio_rdata(5) <= vsync_polarity_internal;
fastio_rdata(7 downto 6) <= "11";
elsif register_number=125 then
-- fastio_rdata <=
-- std_logic_vector(to_unsigned(vic_paint_fsm'pos(debug_paint_fsm_state_drive2),8));
-- fastio_rdata <= std_logic_vector(debug_charaddress_drive2(7 downto 0));
-- fastio_rdata <= x"FF";
-- XXX debug: $D07D shows current single top border height
-- fastio_rdata <= std_logic_vector(single_top_border_200(7 downto 0));
if hypervisor_mode='0' then
case debug_channel_select is
when "00" => fastio_rdata <= std_logic_vector(hyper_data_counter(7 downto 0));
when "01" => fastio_rdata <= std_logic_vector(debug_pixel_red);
when "10" => fastio_rdata <= std_logic_vector(debug_pixel_green);
when "11" => fastio_rdata <= std_logic_vector(debug_pixel_blue);
when others => fastio_rdata <= std_logic_vector(debug_pixel_blue);
end case;
else
-- In hypervisor mode, allow read-back of the debug crosshair positions
-- so that when we freeze and resume, it isn't put into the wrong place
fastio_rdata <= std_logic_vector(debug_x(7 downto 0));
end if;
elsif register_number=126 then
-- fastio_rdata <= "0000"
-- & std_logic_vector(debug_charaddress_drive2(11 downto 8));
-- fastio_rdata <= x"00";
-- fastio_rdata(0) <= external_frame_x_zero_latched;
-- fastio_rdata(1) <= external_pixel_strobe_log(0);
-- fastio_rdata(2) <= vga_in_frame;
-- fastio_rdata(3) <= indisplay_t3;
if hypervisor_mode='0' then
fastio_rdata <= std_logic_vector(hyper_data_counter(15 downto 8));
else
-- In hypervisor mode, allow read-back of the debug crosshair positions
-- so that when we freeze and resume, it isn't put into the wrong place
fastio_rdata <= std_logic_vector(debug_y(7 downto 0));
end if;
elsif register_number=127 then
if hypervisor_mode='0' then
fastio_rdata <= std_logic_vector(hyper_data_counter(23 downto 16));
else
-- In hypervisor mode, allow read-back of the debug crosshair positions
-- so that when we freeze and resume, it isn't put into the wrong place
fastio_rdata(3 downto 0) <= std_logic_vector(debug_x(11 downto 8));
fastio_rdata(7 downto 4) <= std_logic_vector(debug_y(11 downto 8));
end if;
elsif register_number<256 then
-- Fill in unused register space
fastio_rdata <= (others => 'Z');
-- C65 style palette registers
elsif register_number>=256 and register_number<512 then
-- red palette
report "Outputting RED palette read value $" & to_hstring(palette_fastio_rdata(31 downto 24));
palette_fastio_address <= palette_bank_fastio & std_logic_vector(register_number(7 downto 0));
fastio_rdata <= palette_fastio_rdata(31 downto 24);
elsif register_number>=512 and register_number<768 then
-- green palette
report "Outputting GREEN palette read value $" & to_hstring(palette_fastio_rdata(23 downto 16));
palette_fastio_address <= palette_bank_fastio & std_logic_vector(register_number(7 downto 0));
fastio_rdata <= palette_fastio_rdata(23 downto 16);
elsif register_number>=768 and register_number<1024 then
-- blue palette
report "Outputting BLUE palette read value $" & to_hstring(palette_fastio_rdata(15 downto 8));
palette_fastio_address <= palette_bank_fastio & std_logic_vector(register_number(7 downto 0));
fastio_rdata <= palette_fastio_rdata(15 downto 8);
else
fastio_rdata <= (others => 'Z');
end if;
end if;
end if;
if rising_edge(cpuclock) then
if hw_errata_level /= prev_hw_errata_level then
prev_hw_errata_level <= hw_errata_level;
-- Apply variable HW errata level settings
-- HWERRATA:1 VIC-III D016 Delta
if to_integer(hw_errata_level) > 0 then
bug_compat_vic_iii_d016_delta <= 0;
bug_compat_mode <= '0';
else
bug_compat_vic_iii_d016_delta <= 2;
bug_compat_mode <= '1';
end if;
end if;
upscale_enable <= upscale_enable_int;
interlace_mode <= reg_interlace;
mono_mode <= reg_mono;
last_dd00_bits <= dd00_bits;
if last_dd00_bits /= dd00_bits then
viciv_legacy_mode_registers_touched <= '1';
end if;
if reset='0' then
-- Reset sprites to normal behaviour on reset
sprite_horizontal_tile_enables <= (others => '0');
sprite_v400s <= (others => '0');
sprite_v400_super_msbs <= (others => '0');
sprite_alpha_blend_enables <= (others => '0');
sprite_bitplane_enables <= (others => '0');
sprite_extended_width_enables <= (others => '0');
sprite_extended_height_enables <= (others => '0');
sprite_sixteen_colour_enables <= (others => '0');
-- And raster re-write buffer delay also
no_raster_buffer_delay <= '1';
raster_buffer_double_line <= '0';
reg_char_y16 <= '0';
end if;
-- Drive stage for data from hyper RAM and signals out to it
hyper_data <= hyper_data_in;
hyper_data_strobe <= hyper_data_strobe_in;
hyper_addr <= hyper_addr_drive;
hyper_request_toggle_drive2 <= hyper_request_toggle_drive;
hyper_request_toggle_drive3 <= hyper_request_toggle_drive2;
hyper_request_toggle <= hyper_request_toggle_drive3;
if hyper_data_strobe = '1' then
hyper_data_counter <= hyper_data_counter + 1;
end if;
if vicii_ntsc='1' then
display_height <= display_height_ntsc;
else
display_height <= display_height_pal;
end if;
vicii_raster_out(8 downto 0) <= vicii_ycounter_driver;
vicii_raster_out(11 downto 9) <= "000";
hsync_polarity <= hsync_polarity_internal;
vsync_polarity <= vsync_polarity_internal;
vicii_ycounter_driver <= vicii_ycounter;
-- We need a delayed version of the VICII ycounter to display in $D011/$D012,
-- as raster interrupts actually happen one raster line later than expected,
-- to offset the fact that we have a 1 raster line delay in output of the
-- video pipeline.
-- That is, we trigger the interrupt when the raster is actually being DISPLAYED,
-- and make the contents of $D012/$D011 match this.
if enable_raster_delay='1' then
if vicii_ycounter_driver /= 0 then
vicii_ycounter_minus_one <= vicii_ycounter_driver - 1;
else
vicii_ycounter_minus_one <= vicii_max_raster;
end if;
else
vicii_ycounter_minus_one <= vicii_ycounter_driver;
end if;
viciv_calculate_modeline_dimensions;
-- Set IO mode when CPU tells us to. This is done when entering/exiting
-- hypervisor mode.
if iomode_set_toggle /= iomode_set_toggle_last then
iomode_set_toggle_last <= iomode_set_toggle;
viciii_iomode <= iomode_set;
end if;
viciv_fast <= viciv_fast_internal;
viciii_fast <= viciii_fast_internal;
vicii_2mhz <= not vicii_2mhz_internal;
reset_drive <= reset;
if reset_drive='0' then
-- Disable HW errata on reset.
hw_errata_disable_toggle <= not hw_errata_disable_toggle;
-- Allow hyppo ROM to be visible on reset.
rom_at_e000 <= '0';
-- Enable VIC-II/III registers to force video mode settings when touched
vicii_hot_regs_enable <= '1';
-- Set CPU to 40.5MHz
viciv_fast_internal <= '1';
viciii_fast_internal <= '1';
vicii_2mhz_internal <= '0';
-- Clear all VIC-II/III/IV interrupts on reset
mask_collisionspritebitmap <= '0';
mask_collisionspritesprite <= '0';
mask_raster <= '0';
-- Also turn sprites off on reset
-- vicii_sprite_enables <= (others => '0');
end if;
report "drive led = " & std_logic'image(led)
& ", drive motor= " & std_logic'image(motor) severity note;
debug_chargen_active_drive2 <= debug_chargen_active_drive;
debug_chargen_active_soon_drive2 <= debug_chargen_active_soon_drive;
debug_raster_fetch_state_drive2 <= debug_raster_fetch_state_drive;
debug_paint_fsm_state_drive2 <= debug_paint_fsm_state_drive;
debug_charrow_drive2 <= debug_charrow_drive;
debug_charaddress_drive2 <= debug_charaddress_drive;
debug_character_data_from_rom_drive2 <= debug_character_data_from_rom_drive;
debug_screen_ram_buffer_address_drive2 <= debug_screen_ram_buffer_address_drive;
debug_raster_buffer_read_address_drive2 <= debug_raster_buffer_read_address_drive;
debug_raster_buffer_write_address_drive2 <= debug_raster_buffer_write_address_drive;
chargen_active_soon_drive <= chargen_active_soon;
cycles_to_next_card_drive <= cycles_to_next_card;
chargen_active_drive <= chargen_active;
xcounter_drive <= xcounter;
ycounter_drive <= ycounter;
xfrontporch_drive <= xfrontporch;
if viciv_legacy_mode_registers_touched='1' and vicii_hot_regs_enable='1' then
viciv_interpret_legacy_mode_registers;
viciv_update_side_border_dimensions;
viciv_legacy_mode_registers_touched <= '0';
end if;
if viciv_single_side_border_width_touched='1' then
viciv_update_side_border_dimensions;
viciv_single_side_border_width_touched <= '0';
end if;
ack_lightpen <= '0';
ack_collisionspritesprite <= '0';
ack_collisionspritebitmap <= '0';
ack_raster <= '0';
palette_we <= (others => '0');
-- Get VIC-II sprite data offsets
-- (this can happen on cpuclock, since it should still allow ample time
-- to synchronise with the sprites before we fetch the data for them).
-- Save offset delivered by chain
-- report "SPRITE: VIC-II sprite "
-- & integer'image(sprite_number_for_data_rx)
-- & " = " & integer'image(sprite_data_offset_rx);
-- sprite_data_offsets(sprite_number_for_data_rx) <= sprite_data_offset_rx;
-- -- Ask for the next one (8 sprites + 8 C65 bitplanes)
-- if sprite_number_counter = 15 then
-- sprite_number_counter <= 0;
-- sprite_number_for_data_tx <= 0;
-- else
-- sprite_number_counter <= sprite_number_counter + 1;
-- sprite_number_for_data_tx <= sprite_number_for_data_tx + 1;
-- end if;
-- Reading some registers clears IRQ flags
clear_collisionspritebitmap_1 <= '0';
clear_collisionspritesprite_1 <= '0';
if fastio_read='1' then
if register_number=30 then
-- @IO:C64 $D01E sprite/sprite collissions
clear_collisionspritesprite_1 <= '1';
elsif register_number=31 then
-- @IO:C64 $D01F sprite/foreground collissions
clear_collisionspritebitmap_1 <= '1';
end if;
end if;
-- One cycle delay so that CPU can read these registers with 1 cycle
-- wait-state without the collision bits disappearing before the CPU
-- latches the value.
clear_collisionspritebitmap <= clear_collisionspritebitmap_1;
clear_collisionspritesprite <= clear_collisionspritesprite_1;
-- $D000 registers
if fastio_write='1'
and (fastio_addr(19) = '0' or fastio_addr(19) = '1') then
if register_number>=0 and register_number<8 then
-- compatibility sprite coordinates
-- @IO:C64 $D000 VIC-II:S0X@SNX sprite N horizontal position
-- @IO:C64 $D001 VIC-II:S0Y@SNY sprite N vertical position
-- @IO:C64 $D002 VIC-II:S1X @SNX
-- @IO:C64 $D003 VIC-II:S1Y @SNY
-- @IO:C64 $D004 VIC-II:S2X @SNX
-- @IO:C64 $D005 VIC-II:S2Y @SNY
-- @IO:C64 $D006 VIC-II:S3X @SNX
-- @IO:C64 $D007 VIC-II:S3Y @SNY
sprite_x(safe_to_integer(register_num(2 downto 0))) <= unsigned(fastio_wdata);
elsif register_number<16 then
-- @IO:C64 $D008 VIC-II:S4X @SNX
-- @IO:C64 $D009 VIC-II:S4Y @SNY
-- @IO:C64 $D00A VIC-II:S5X @SNX
-- @IO:C64 $D00B VIC-II:S5Y @SNY
-- @IO:C64 $D00C VIC-II:S6X @SNX
-- @IO:C64 $D00D VIC-II:S6Y @SNY
-- @IO:C64 $D00E VIC-II:S7X @SNX
-- @IO:C64 $D00F VIC-II:S7Y @SNY
sprite_y(safe_to_integer(register_num(2 downto 0))) <= unsigned(fastio_wdata);
elsif register_number=16 then
-- @IO:C64 $D010 VIC-II:SXMSB sprite horizontal position MSBs
vicii_sprite_xmsbs <= fastio_wdata;
elsif register_number=17 then -- $D011
report "D011 WRITTEN" severity note;
-- @IO:C64 $D011 VIC-II control register
-- @IO:C64 $D011.7 VIC-II:RC8 raster compare bit 8
vicii_raster_compare(10 downto 8) <= "00" & fastio_wdata(7);
vicii_is_raster_source <= '1';
-- @IO:C64 $D011.6 VIC-II:ECM extended background mode
extended_background_mode <= fastio_wdata(6);
-- @IO:C64 $D011.5 VIC-II:BMM bitmap mode
text_mode <= not fastio_wdata(5);
-- @IO:C64 $D011.4 VIC-II:BLNK Enable display: 0 = blank the display, 1 = show the display
blank <= not fastio_wdata(4);
-- @IO:C64 $D011.3 VIC-II:RSEL 24/25 row select
twentyfourlines <= not fastio_wdata(3);
-- @IO:C64 $D011.2-0 VIC-II:YSCL 24/25 vertical smooth scroll
vicii_y_smoothscroll <= unsigned(fastio_wdata(2 downto 0));
viciv_legacy_mode_registers_touched <= '1';
elsif register_number=18 then
-- @IO:C64 $D012 VIC-II:RC raster compare bits 0 to 7
vicii_raster_compare(7 downto 0) <= unsigned(fastio_wdata);
vicii_is_raster_source <= '1';
elsif register_number=19 then
-- @IO:C64 $D013 VIC-II:LPX Coarse horizontal beam position (was lightpen X)
elsif register_number=20 then
-- @IO:C64 $D014 VIC-II:LPY Coarse vertical beam position (was lightpen Y)
elsif register_number=21 then
-- @IO:C64 $D015 VIC-II:SE sprite enable bits
vicii_sprite_enables <= fastio_wdata;
elsif register_number=22 then
-- @IO:C64 $D016 VIC-II control register
-- @IO:C64 $D016.5 VIC-II:RST Disables video output on MAX Machine(tm) VIC-II 6566. Ignored on normal C64s and the MEGA65
-- @IO:C64 $D016.4 VIC-II:MCM Multi-colour mode
multicolour_mode <= fastio_wdata(4);
-- @IO:C64 $D016.3 VIC-II:CSEL 38/40 column select
thirtyeightcolumns <= not fastio_wdata(3);
-- @IO:C64 $D016.2-0 VIC-II:XSCL horizontal smooth scroll
vicii_x_smoothscroll <= unsigned(fastio_wdata(2 downto 0));
viciv_legacy_mode_registers_touched <= '1';
elsif register_number=23 then
-- @IO:C64 $D017 VIC-II:SEXY sprite vertical expansion enable bits
vicii_sprite_y_expand <= fastio_wdata;
elsif register_number=24 then
-- @IO:C64 $D018 VIC-II RAM addresses
-- Character set source address for user-generated character sets.
-- @IO:C64 $D018.3-1 VIC-II:CB character set address location ($\times$ 1KiB)
character_set_address(13 downto 11) <= unsigned(fastio_wdata(3 downto 1));
character_set_address(10 downto 0) <= (others => '0');
-- Bits 14 and 15 get set by writing to $DD00, as the VIC-IV sniffs
-- that CIA register being written on the fastio bus.
-- Writing here also automatically clears the bank select bits for
-- the screen RAM address, so that writing to $D018 always works as expected.
screen_ram_base(19 downto 16) <= "0000";
-- @IO:C64 $D018.7-4 VIC-II:VS screen address ($\times$ 1KiB)
reg_d018_screen_addr <= unsigned(fastio_wdata(7 downto 4));
viciv_legacy_mode_registers_touched <= '1';
elsif register_number=25 then
-- @IO:C64 $D019 VIC-II IRQ control
-- Acknowledge IRQs
-- (we need to pass this to the dotclock side to avoide multiple drivers)
-- @IO:C64 $D019.3 VIC-II:ILP light pen indicate or acknowledge
ack_lightpen <= fastio_wdata(3);
-- @IO:C64 $D019.2 VIC-II:ISSC sprite:sprite collision indicate or acknowledge
ack_collisionspritesprite <= fastio_wdata(2);
-- @IO:C64 $D019.1 VIC-II:ISBC sprite:bitmap collision indicate or acknowledge
ack_collisionspritebitmap <= fastio_wdata(1);
-- @IO:C64 $D019.0 VIC-II:RIRQ raster compare indicate or acknowledge
ack_raster <= fastio_wdata(0);
elsif register_number=26 then
-- @IO:C64 $D01A compatibility IRQ mask bits
-- XXX Enable/disable IRQs
-- @IO:C64 $D01A.2 VIC-II:MISSC mask sprite:sprite collision IRQ
mask_collisionspritesprite <= fastio_wdata(2);
-- @IO:C64 $D01A.1 VIC-II:MISBC mask sprite:bitmap collision IRQ
mask_collisionspritebitmap <= fastio_wdata(1);
-- @IO:C64 $D01A.0 VIC-II:MRIRQ mask raster IRQ
mask_raster <= fastio_wdata(0);
elsif register_number=27 then
-- @IO:C64 $D01B VIC-II:BSP sprite background priority bits
vicii_sprite_priority_bits <= fastio_wdata;
elsif register_number=28 then
-- @IO:C64 $D01C VIC-II:SCM sprite multicolour enable bits
vicii_sprite_multicolour_bits <= fastio_wdata;
elsif register_number=29 then
-- @IO:C64 $D01D VIC-II:SEXX sprite horizontal expansion enable bits
vicii_sprite_x_expand <= fastio_wdata;
elsif register_number=30 then
-- @IO:C64 $D01E VIC-II:SSC sprite/sprite collision indicate bits
-- vicii_sprite_sprite_collisions <= fastio_wdata;
elsif register_number=31 then
-- @IO:C64 $D01F VIC-II:SBC sprite/foreground collision indicate bits
-- vicii_sprite_bitmap_collisions <= fastio_wdata;
elsif register_number=32 then
-- @IO:C64 $D020 Border colour
-- @IO:C64 $D020.3-0 VIC-II:BORDERCOL display border colour (16 colour)
-- @IO:C65 $D020.7-0 VIC-III:BORDERCOL display border colour (256 colour)
-- @IO:GS $D020.7-0 VIC-IV:BORDERCOL display border colour (256 colour)
if register_bank=x"D0" then
border_colour(3 downto 0) <= unsigned(fastio_wdata(3 downto 0));
else
border_colour <= unsigned(fastio_wdata);
end if;
elsif register_number=33 then
-- @IO:C64 $D021 Screen colour
-- @IO:C64 $D021.3-0 VIC-II:SCREENCOL screen colour (16 colour)
-- @IO:C65 $D021.7-0 VIC-III:SCREENCOL screen colour (256 colour)
-- @IO:GS $D021.7-0 VIC-IV:SCREENCOL screen colour (256 colour)
if register_bank=x"D0" then
screen_colour(3 downto 0) <= unsigned(fastio_wdata(3 downto 0));
else
screen_colour <= unsigned(fastio_wdata);
end if;
elsif register_number=34 then
-- @IO:C64 $D022 VIC-II multi-colour 1
-- @IO:C64 $D022.3-0 VIC-II:MC1 multi-colour 1 (16 colour)
-- @IO:C65 $D022.7-0 VIC-III:MC1 multi-colour 1 (256 colour)
-- @IO:GS $D022.7-0 VIC-IV:MC1 multi-colour 1 (256 colour)
if register_bank=x"D0" then
multi1_colour <= unsigned("0000"&fastio_wdata(3 downto 0));
else
multi1_colour <= unsigned(fastio_wdata);
end if;
elsif register_number=35 then
-- @IO:C64 $D023 VIC-II multi-colour 2
-- @IO:C64 $D023.3-0 VIC-II:MC2 multi-colour 2 (16 colour)
-- @IO:C65 $D023.7-0 VIC-III:MC2 multi-colour 2 (256 colour)
-- @IO:GS $D023.7-0 VIC-IV:MC2 multi-colour 2 (256 colour)
if register_bank=x"D0" then
multi2_colour <= unsigned("0000"&fastio_wdata(3 downto 0));
else
multi2_colour <= unsigned(fastio_wdata);
end if;
elsif register_number=36 then
-- @IO:C64 $D024 VIC-II multi-colour 3
-- @IO:C64 $D024.3-0 VIC-II:MC3 multi-colour 3 (16 colour)
-- @IO:C65 $D024.7-0 VIC-III:MC3 multi-colour 3 (256 colour)
-- @IO:GS $D024.7-0 VIC-IV:MC3 multi-colour 3 (256 colour)
if register_bank=x"D0" then
multi3_colour <= unsigned("0000"&fastio_wdata(3 downto 0));
else
multi3_colour <= unsigned(fastio_wdata);
end if;
elsif register_number=37 then
-- @IO:C64 $D025 VIC-II:SPRMC0 Sprite multi-colour 0
-- @IO:C65 $D025 VIC-III:SPRMC0 Sprite multi-colour 0 (8-bit for selection of any palette colour)
-- @IO:GS $D025 VIC-IV:SPRMC0 Sprite multi-colour 0 (8-bit for selection of any palette colour)
if register_bank=x"D0" then
sprite_multi0_colour <= unsigned("0000"&fastio_wdata(3 downto 0));
else
sprite_multi0_colour <= unsigned(fastio_wdata);
end if;
elsif register_number=38 then
-- @IO:C64 $D026 VIC-II:SPRMC1 Sprite multi-colour 1
-- @IO:C65 $D026 VIC-III:SPRMC1 Sprite multi-colour 1 (8-bit for selection of any palette colour)
-- @IO:GS $D026 VIC-IV:SPRMC1 Sprite multi-colour 1 (8-bit for selection of any palette colour)
if register_bank=x"D0" then
sprite_multi1_colour <= unsigned("0000"&fastio_wdata(3 downto 0));
else
sprite_multi1_colour <= unsigned(fastio_wdata);
end if;
elsif register_number>=39 and register_number<=46 then
-- @IO:C64 $D027 VIC-II:SPR0COL@SPRNCOL sprite N colour / 16-colour sprite transparency colour (lower nybl)
-- @IO:C64 $D028 VIC-II:SPR1COL @SPRNCOL
-- @IO:C64 $D029 VIC-II:SPR2COL @SPRNCOL
-- @IO:C64 $D02A VIC-II:SPR3COL @SPRNCOL
-- @IO:C64 $D02B VIC-II:SPR4COL @SPRNCOL
-- @IO:C64 $D02C VIC-II:SPR5COL @SPRNCOL
-- @IO:C64 $D02D VIC-II:SPR6COL @SPRNCOL
-- @IO:C64 $D02E VIC-II:SPR7COL @SPRNCOL
if register_bank=x"D0" then
sprite_colours(safe_to_integer(register_number)-39)(3 downto 0) <= unsigned(fastio_wdata(3 downto 0));
else
sprite_colours(safe_to_integer(register_number)-39) <= unsigned(fastio_wdata);
end if;
-- Skip $D02F - $D047 to avoid real C65/C128 programs trying to
-- fiddle with registers in this range.
-- NEW VIDEO REGISTERS
elsif register_number=47 then
-- @IO:C64 $D02F VIC-II:KEY Write $00 then $00 to enable C64/VIC-II IO registers
-- this is actually the default when not hitting any of the other keys, but we
-- promote writing 00, 00 to keep it more transparent for further expansions.
viciii_iomode <= "00"; -- by default go back to VIC-II mode
-- @IO:C65 $D02F VIC-III:KEY Write $A5 then $96 to enable C65/VIC-III IO registers
if reg_key=x"a5" then
if fastio_wdata=x"96" then
-- C65 VIC-III mode
viciii_iomode <= "01";
end if;
-- @IO:GS $D02F VIC-IV:KEY Write $47 then $53 to enable MEGA65/VIC-IV IO registers
elsif reg_key=x"47" then
if fastio_wdata=x"53" then
-- MEGA65 VIC-IV mode
viciii_iomode <= "11";
end if;
-- @IO:GS $D02F ETH:KEY Write $45 then $54 to map 45E100 ethernet controller buffers to $D000-$DFFF
elsif reg_key=x"45" then
if fastio_wdata=x"54" then
-- MEGA65 Map ethernet frame buffer mode
viciii_iomode <= "10";
end if;
end if;
reg_key <= unsigned(fastio_wdata);
elsif register_number=255 then
-- @IO:C64 $D030 SUMMARY: C128 2MHz emulation
-- @IO:C64 $D030.0 VIC-II:C128!FAST 2MHz select (for C128 2MHz emulation)
vicii_2mhz_internal <= fastio_wdata(0);
elsif register_number=48 then
-- @IO:C65 $D030 SUMMARY:VIC-III Control Register A
-- @IO:C65 $D030.7 VIC-III:ROME Map C65 ROM @ $E000
rom_at_e000 <= fastio_wdata(7);
reg_rom_e000 <= fastio_wdata(7);
-- @IO:C65 $D030.6 VIC-III:CROM9 Select between C64 and C65 charset (not implemented)
reg_c65_charset <= fastio_wdata(6);
-- @IO:C65 $D030.5 VIC-III:ROMC Map C65 ROM @ $C000
rom_at_c000 <= fastio_wdata(5);
reg_rom_c000 <= fastio_wdata(5);
-- @IO:C65 $D030.4 VIC-III:ROMA Map C65 ROM @ $A000
rom_at_a000 <= fastio_wdata(4);
reg_rom_a000 <= fastio_wdata(4);
-- @IO:C65 $D030.3 VIC-III:ROM8 Map C65 ROM @ $8000
rom_at_8000 <= fastio_wdata(3);
reg_rom_8000 <= fastio_wdata(3);
-- @IO:C65 $D030.2 VIC-III:PAL Use PALETTE ROM (0) or RAM (1) entries for colours 0 - 15
reg_palrom <= fastio_wdata(2);
-- @IO:C65 $D030.1 VIC-III:EXTSYNC Enable external video sync (genlock input)
-- @IO:C65 $D030.0 VIC-III:CRAM2K Map 2nd KB of colour RAM @ $DC00-$DFFF
colourram_at_dc00_internal<= fastio_wdata(0);
colourram_at_dc00<= fastio_wdata(0);
elsif register_number=49 then
if d031_writes /= x"FF" then
d031_writes <= d031_writes + 1;
d031_written_internal <= not d031_written_internal;
else
d031_writes <= x"00";
end if;
-- @IO:C65 $D031 SUMMARY:VIC-III Control Register B
-- @IO:C65 $D031.7 VIC-III:H640 Enable C64 640 horizontal pixels / 80 column mode
reg_h640 <= fastio_wdata(7);
-- @IO:C65 $D031.6 VIC-III:FAST Enable C65 FAST mode (~3.5MHz)
viciii_fast_internal <= fastio_wdata(6);
-- @IO:C65 $D031.5 VIC-III:ATTR Enable extended attributes and 8 bit colour entries
viciii_extended_attributes <= fastio_wdata(5);
-- @IO:C65 $D031.4 VIC-III:BPM Bit-Plane Mode
bitplane_mode <= fastio_wdata(4);
-- @IO:C65 $D031.3 VIC-III:V400 Enable 400 vertical pixels (disables PALEMU)
reg_v400 <= fastio_wdata(3);
-- @IO:C65 $D031.2 VIC-III:H1280 Enable 1280 horizontal pixels (not implemented, disables PALEMU)
reg_h1280 <= fastio_wdata(2);
-- @IO:C65 $D031.1 VIC-III:MONO Enable VIC-III MONO composite video output (colour if disabled)
reg_mono <= fastio_wdata(1);
-- @IO:C65 $D031.0 VIC-III:INT Enable VIC-III interlaced mode
-- Auto-enable interlace mode when selecting V400 (unless in
-- hypervisor, in which case we want to be able to unfreeze this
-- register without side-effects)
-- Note: This has been disabled again as interlace mode was breaking display on some hdmi monitors
-- We need to come up with a configurable solution for composite once it is ready
-- if reg_v400='0' and fastio_wdata(3)='1' and hypervisor_mode='0' then
-- reg_interlace <= '1';
-- else
reg_interlace <= fastio_wdata(0);
-- end if;
viciv_legacy_mode_registers_touched <= '1';
elsif register_number=50 then
bitplane_enables <= fastio_wdata;
-- @IO:C65 $D033.5-7 VIC-III:B0ADODD@BXADODD Odd rows of even Bitplane X address[15:13] (only used in v400 mode)
-- @IO:C65 $D033.1-3 VIC-III:B0ADEVN@BXADEVN Even rows of even Bitplane X address[15:13] (for v200, even row drawn twice)
-- @IO:C65 $D034.5-7 VIC-III:B1ADODD@BYADODD Odd rows of odd Bitplane Y address[15:13] (+64KB) (only used in v400 mode)
-- @IO:C65 $D034.1-3 VIC-III:B1ADEVN@BYADEVN Even rows of odd Bitplane Y address[15:13] (+64KB) (for v200, even row drawn twice)
-- @IO:C65 $D035.5-7 VIC-III:B2ADODD @BXADODD
-- @IO:C65 $D035.1-3 VIC-III:B2ADEVN @BXADEVN
-- @IO:C65 $D036.5-7 VIC-III:B3ADODD @BYADODD
-- @IO:C65 $D036.1-3 VIC-III:B3ADEVN @BYADEVN
-- @IO:C65 $D037.5-7 VIC-III:B4ADODD @BXADODD
-- @IO:C65 $D037.1-3 VIC-III:B4ADEVN @BXADEVN
-- @IO:C65 $D038.5-7 VIC-III:B5ADODD @BYADODD
-- @IO:C65 $D038.1-3 VIC-III:B5ADEVN @BYADEVN
-- @IO:C65 $D039.5-7 VIC-III:B6ADODD @BXADODD
-- @IO:C65 $D039.1-3 VIC-III:B6ADEVN @BXADEVN
-- @IO:C65 $D03A.5-7 VIC-III:B7ADODD @BYADODD
-- @IO:C65 $D03A.1-3 VIC-III:B7ADEVN @BYADEVN
elsif register_number >= 51 and register_number <= 58 then
-- @IO:C65 $D033-$D03A - VIC-III Bitplane addresses
--bitplane_number := safe_to_integer(register_number(3 downto 0)) - 3;
bitplane_addresses(safe_to_integer(register_number)-51) <= unsigned(fastio_wdata);
-- @IO:C65 $D03B VIC-III:BPCOMP Complement bitplane flags
elsif register_number=59 then
bitplane_complements <= fastio_wdata;
-- @IO:C65 $D03C VIC-III:BPX Bitplane X
elsif register_number=60 then
dat_x <= unsigned(fastio_wdata(6 downto 0));
dat_y(8) <= fastio_wdata(7);
-- @IO:C65 $D03D VIC-III:BPY Bitplane Y
elsif register_number=61 then
dat_y(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=64 then
-- @IO:C65 $D03E VIC-III:HPOS Bitplane X Offset
elsif register_number=62 then
bitplanes_x_start <= unsigned(fastio_wdata);
-- @IO:C65 $D03F VIC-III:VPOS Bitplane Y Offset
elsif register_number=63 then
bitplanes_y_start <= unsigned(fastio_wdata);
elsif register_number=64 then
-- @IO:C65 $D040 VIC-III:B0PIX@BNPIX Display Address Translater (DAT) Bitplane N port
elsif register_number=65 then
-- @IO:C65 $D041 VIC-III:B1PIX @BNPIX
elsif register_number=66 then
-- @IO:C65 $D042 VIC-III:B2PIX @BNPIX
elsif register_number=67 then
-- @IO:C65 $D043 VIC-III:B3PIX @BNPIX
elsif register_number=68 then
-- @IO:C65 $D044 VIC-III:B4PIX @BNPIX
elsif register_number=69 then
-- @IO:C65 $D045 VIC-III:B5PIX @BNPIX
elsif register_number=70 then
-- @IO:C65 $D046 VIC-III:B6PIX @BNPIX
elsif register_number=71 then
-- @IO:C65 $D047 VIC-III:B7PIX @BNPIX
elsif register_number=72 then
-- @IO:GS $D048 VIC-IV:TBDRPOS top border position
border_y_top(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=73 then
-- @IO:GS $D049.3-0 VIC-IV:TBDRPOS top border position MSB
border_y_top(11 downto 8) <= unsigned(fastio_wdata(3 downto 0));
-- @IO:GS $D049.7-4 VIC-IV:SPRBPMEN Sprite bitplane-modify-mode enables
sprite_bitplane_enables(3 downto 0) <= fastio_wdata(7 downto 4);
elsif register_number=74 then
-- @IO:GS $D04A VIC-IV:BBDRPOS bottom border position
border_y_bottom(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=75 then
-- @IO:GS $D04B.3-0 VIC-IV:BBDRPOS bottom border position
border_y_bottom(11 downto 8) <= unsigned(fastio_wdata(3 downto 0));
-- @IO:GS $D04B.7-4 VIC-IV:SPRBPMEN Sprite bitplane-modify-mode enables
sprite_bitplane_enables(7 downto 4) <= fastio_wdata(7 downto 4);
elsif register_number=76 then
-- @IO:GS $D04C VIC-IV:TEXTXPOS character generator horizontal position
x_chargen_start(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=77 then
-- @IO:GS $D04D.3-0 VIC-IV:TEXTXPOS character generator horizontal position
x_chargen_start(11 downto 8) <= unsigned(fastio_wdata(3 downto 0));
-- @IO:GS $D04D.7-4 VIC-IV:SPRTILEN Sprite horizontal tile enables.
sprite_horizontal_tile_enables(3 downto 0) <= fastio_wdata(7 downto 4);
elsif register_number=78 then
-- @IO:GS $D04E VIC-IV:TEXTYPOS Character generator vertical position
y_chargen_start(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=79 then
-- @IO:GS $D04F.3-0 VIC-IV:TEXTYPOS Character generator vertical position
y_chargen_start(11 downto 8) <= unsigned(fastio_wdata(3 downto 0));
-- @IO:GS $D04F.7-4 VIC-IV:SPRTILEN Sprite 7-4 horizontal tile enables
sprite_horizontal_tile_enables(7 downto 4) <= fastio_wdata(7 downto 4);
elsif register_number=80 then
-- @IO:GS $D050 VIC-IV:XPOSLSB Read horizontal raster scan position LSB
viciv_rasterx_compare(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=81 then
-- @IO:GS $D051.0-5 VIC-IV:XPOSMSB Read horizontal raster scan position MSB
viciv_rasterx_compare(13 downto 8) <= unsigned(fastio_wdata(5 downto 0));
-- @IO:GS $D051.6 VIC-IV:DBLRR When set, the Raster Rewrite Buffer is only updated every 2nd raster line, limiting resolution to V200, but allowing more cycles for Raster-Rewrite actions.
raster_buffer_double_line <= fastio_wdata(6);
-- @IO:GS $D051.7 VIC-IV:NORRDEL When clear, raster rewrite double buffering is used
no_raster_buffer_delay <= fastio_wdata(7);
elsif register_number=82 then
-- @IO:GS $D052 VIC-IV:FNRASTERLSB Read physical raster position
-- Allow setting of fine raster for IRQ (low bits)
-- vicii_raster_compare(7 downto 0) <= unsigned(fastio_wdata);
-- vicii_is_raster_source <= '0';
elsif register_number=83 then
-- @IO:GS $D053.0-2 VIC-IV:FN!RASTER!MSB Read physical raster position
-- @IO:GS $D053.4 VIC-IV:RESERVED Reserved
-- @IO:GS $D053.5 VIC-IV:UPSCALE Enable integrated low-latency (130usec) 720p upscaler
-- @IO:GS $D053.6 VIC-IV:SHDEMU Enable simulated shadow-mask (PALEMU must also be enabled)
-- Allow setting of fine raster for IRQ (high bits)
-- vicii_raster_compare(10 downto 8) <= unsigned(fastio_wdata(2 downto 0));
-- @IO:GS $D053.7 VIC-IV:FNRST Read raster compare source (0=VIC-IV fine raster, 1=VIC-II raster), provides same value as set in FNRSTCMP
shadow_mask_enable <= fastio_wdata(6);
upscale_enable_int <= fastio_wdata(5);
elsif register_number=84 then
-- @IO:GS $D054 SUMMARY:VIC-IV Control register C
-- @IO:GS $D054.7 VIC-IV:ALPHEN Alpha compositor enable
compositer_enable <= fastio_wdata(7);
-- @IO:GS $D054.6 VIC-IV:VFAST MEGA65 FAST mode (40.5MHz)
viciv_fast_internal <= fastio_wdata(6);
-- @IO:GS $D054.5 VIC-IV:PALEMU Enable PAL CRT-like scan-line emulation (disabled by V400 or H1280)
pal_simulate <= fastio_wdata(5);
-- @IO:GS $D054.4 VIC-IV:SPR!H640 Sprite H640 enable
sprite_h640 <= fastio_wdata(4);
-- @IO:GS $D054.3 VIC-IV:SMTH video output horizontal smoothing enable
horizontal_filter <= fastio_wdata(3);
-- @IO:GS $D054.2 VIC-IV:FCLRHI enable full-colour mode for character numbers >$FF
fullcolour_extendedchars <= fastio_wdata(2);
-- @IO:GS $D054.1 VIC-IV:FCLRLO enable full-colour mode for character numbers <=$FF
fullcolour_8bitchars <= fastio_wdata(1);
-- @IO:GS $D054.0 VIC-IV:CHR16 enable 16-bit character numbers (two screen bytes per character)
sixteenbit_charset <= fastio_wdata(0);
elsif register_number=85 then
-- @IO:GS $D055 VIC-IV:SPRHGTEN sprite extended height enable (one bit per sprite)
sprite_extended_height_enables <= fastio_wdata;
elsif register_number=86 then
-- @IO:GS $D056 VIC-IV:SPRHGHT Sprite extended height size (sprite pixels high)
sprite_extended_height_size <= unsigned(fastio_wdata);
elsif register_number=87 then
-- @IO:GS $D057 VIC-IV:SPRX64EN Sprite extended width enables (8 bytes per sprite row = 64 pixels wide for normal sprites or 16 pixels wide for 16-colour sprite mode)
sprite_extended_width_enables <= fastio_wdata;
elsif register_number=88 then
-- @IO:GS $D058 VIC-IV:LINESTEPLSB number of bytes to advance between each text row (LSB)
virtual_row_width(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=89 then
-- @IO:GS $D059 VIC-IV:LINESTEPMSB number of bytes to advance between each text row (MSB)
virtual_row_width(15 downto 8) <= unsigned(fastio_wdata);
elsif register_number=90 then
-- @IO:GS $D05A VIC-IV:CHRXSCL Horizontal hardware scale of text mode (pixel 120ths per pixel)
chargen_x_scale <= unsigned(fastio_wdata);
elsif register_number=91 then
-- @IO:GS $D05B VIC-IV:CHRYSCL Vertical scaling of text mode (number of physical rasters per char text row)
chargen_y_scale <= unsigned(fastio_wdata);
elsif register_number=92 then
-- @IO:GS $D05C VIC-IV:SDBDRWD!LSB Width of single side border (LSB)
single_side_border(7 downto 0) <= unsigned(fastio_wdata);
viciv_single_side_border_width_touched <= '1';
elsif register_number=93 then
-- @IO:GS $D05D.0-5 VIC-IV:SDBDRWD!MSB side border width (MSB)
single_side_border(13 downto 8) <= unsigned(fastio_wdata(5 downto 0));
viciv_single_side_border_width_touched <= '1';
-- @IO:GS $D05D.6 VIC-IV:RST!DELEN Enable raster delay (delays raster counter and interrupts by one line to match output pipeline latency)
enable_raster_delay <= fastio_wdata(6);
-- @IO:GS $D05D.7 VIC-IV:HOTREG Enable VIC-II hot registers. When enabled, touching many VIC-II registers causes the VIC-IV to recalculate display parameters, such as border positions and sizes. Touching registers while this is disabled will trigger a change when reenabling. Setting this to 0 will clear the recalc flag, canceling the recalculation.
vicii_hot_regs_enable <= fastio_wdata(7);
if fastio_wdata(7) = '0' then
viciv_legacy_mode_registers_touched <= '0';
end if;
elsif register_number=94 then
-- @IO:GS $D05E VIC-IV:CHRCOUNT Number of characters to display per row (LSB)
display_row_width(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=95 then
-- @IO:GS $D05F VIC-IV:SPRXSMSBS Sprite H640 X Super-MSBs
sprite_h640_msbs <= fastio_wdata;
elsif register_number=96 then
-- @IO:GS $D060 VIC-IV:SCRNPTRLSB screen RAM precise base address (bits 7 - 0)
screen_ram_base(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=97 then
-- @IO:GS $D061 VIC-IV:SCRNPTRMSB screen RAM precise base address (bits 15 - 8)
screen_ram_base(15 downto 8) <= unsigned(fastio_wdata);
elsif register_number=98 then
-- @IO:GS $D062 VIC-IV:SCRNPTRBNK screen RAM precise base address (bits 23 - 16)
screen_ram_base(23 downto 16) <= unsigned(fastio_wdata);
elsif register_number=99 then
-- @IO:GS $D063.0-3 VIC-IV:SCRNPTRMB screen RAM precise base address (bits 27 - 24)
screen_ram_base(27 downto 24) <= unsigned(fastio_wdata(3 downto 0));
-- @IO:GS $D063.4-5 VIC-IV:CHRCOUNT Number of characters to display per
-- row (MSBs)
display_row_width(9 downto 8) <= unsigned(fastio_wdata(5 downto 4));
-- @IO:GS $D063.6 VIC-IV:FCOLMCM enable 256 colours in multicolour text mode
fullcolour_mcm <= fastio_wdata(6);
-- @IO:GS $D063.7 VIC-IV:EXGLYPH source full-colour character data from expansion RAM
glyphs_from_hyperram <= fastio_wdata(7);
elsif register_number=100 then
-- @IO:GS $D064 VIC-IV:COLPTRLSB colour RAM base address (bits 0 - 7)
colour_ram_base(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=101 then
-- @IO:GS $D065 VIC-IV:COLPTRMSB colour RAM base address (bits 15 - 8)
colour_ram_base(15 downto 8) <= unsigned(fastio_wdata);
elsif register_number=102 then -- $D3066
-- @IO:GS $D066.0-4 VIC-IV xcounter pipeline delay DEBUG WILL BE REMOVED
-- @IO:GS $D066.6 VIC-IV render activity display enable DEBUG WILL BE REMOVED
-- @IO:GS $D066.7 VIC-IV test pattern display enable DEBUG WILL BE REMOVED
reg_xcounter_delay <= safe_to_integer(unsigned(fastio_wdata(4 downto 0)));
show_render_activity <= fastio_wdata(6);
test_pattern_enable <= fastio_wdata(7);
elsif register_number=103 then -- $D3067
-- @IO:GS $D067 DEBUG:SBPDEBUG Sprite/bitplane first X DEBUG WILL BE REMOVED
sprite_first_x(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=104 then
-- @IO:GS $D068 VIC-IV:CHARPTRLSB Character set precise base address (bits 0 - 7)
character_set_address(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=105 then
-- @IO:GS $D069 VIC-IV:CHARPTRMSB Character set precise base address (bits 15 - 8)
character_set_address(15 downto 8) <= unsigned(fastio_wdata);
elsif register_number=106 then
-- @IO:GS $D06A VIC-IV:CHARPTRBNK Character set precise base address (bits 23 - 16)
character_set_address(23 downto 16) <= unsigned(fastio_wdata);
elsif register_number=107 then
-- @IO:GS $D06B VIC-IV:SPR16EN sprite 16-colour mode enables
sprite_sixteen_colour_enables <= fastio_wdata;
elsif register_number=108 then
-- @IO:GS $D06C VIC-IV:SPRPTRADRLSB sprite pointer address (bits 7 - 0)
vicii_sprite_pointer_address(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=109 then
-- @IO:GS $D06D VIC-IV:SPRPTRADRMSB sprite pointer address (bits 15 - 8)
vicii_sprite_pointer_address(15 downto 8) <= unsigned(fastio_wdata);
elsif register_number=110 then
-- @IO:GS $D06E.0-6 VIC-IV:SPRPTRBNK sprite pointer address (bits 23 - 16)
-- @IO:GS $D06E.7 VIC-IV:SPR!PTR16 16-bit sprite pointer mode (allows sprites to be located on any 64 byte boundary in chip RAM)
vicii_sprite_pointer_address(23 downto 16) <= unsigned(fastio_wdata);
elsif register_number=111 then
-- @IO:GS $D06F.5-0 VIC-IV:RASLINE0 first VIC-II raster line
vicii_first_raster(5 downto 0) <= unsigned(fastio_wdata(5 downto 0));
-- @IO:GS $D06F.6 VIC-IV:VGAHDTV Select more VGA-compatible mode if set, instead of HDMI/HDTV VIC-II cycle-exact frame timing. May help to produce a functional display on older VGA monitors.
-- @IO:GS $D06F.7 VIC-IV:PALNTSC NTSC emulation mode (max raster = 262)
vicii_ntsc <= fastio_wdata(7);
pal50_select <= not fastio_wdata(7);
vga60_select <= fastio_wdata(6);
vga60_select_internal <= fastio_wdata(6);
-- Make sure that matrix
-- mode display isn't jiggly
if fastio_wdata(7)='1' then
reg_xcounter_delay <= 1;
reg_alpha_delay <= x"1";
else
reg_xcounter_delay <= 0;
reg_alpha_delay <= x"1";
end if;
report "LEGACY register update & PAL/NTSC mode select";
-- Recompute screen and border positions
-- But only if not in hypervisor mode, so that we don't mess up freezing
if hypervisor_mode='0' then
viciv_single_side_border_width_touched <= '1';
end if;
if vicii_ntsc /= fastio_wdata(7) or vga60_select_internal /= fastio_wdata(6) then
case fastio_wdata(7 downto 6) is
when "00" => -- PAL, 720x576 @ 50Hz
sprite_y_adjust <= to_unsigned(0,8);
vicii_ycounter_scale_minus_zero <= to_unsigned(2-1,4);
vicii_max_raster <= pal_max_raster;
-- VSYNC is negative for 50Hz (required for some monitors)
hsync_polarity_internal <= '1';
vsync_polarity_internal <= '0';
if vicii_ntsc /= fastio_wdata(7) then
vicii_first_raster <= to_unsigned(0,9);
end if;
when "01" => -- PAL, 720x576 50Hz, NTSC max raster
sprite_y_adjust <= to_unsigned(0,8);
vicii_ycounter_scale_minus_zero <= to_unsigned(2-1,4);
vicii_max_raster <= ntsc_max_raster;
hsync_polarity_internal <= '1';
vsync_polarity_internal <= '0';
if vicii_ntsc /= fastio_wdata(7) then
vicii_first_raster <= to_unsigned(0,9);
end if;
when "10" => -- NTSC, 720x480 @ 60Hz
sprite_y_adjust <= to_unsigned(24,8);
vicii_ycounter_scale_minus_zero <= to_unsigned(2-1,4);
vicii_max_raster <= ntsc_max_raster;
hsync_polarity_internal <= '1';
vsync_polarity_internal <= '0';
if vicii_ntsc /= fastio_wdata(7) then
vicii_first_raster <= to_unsigned(7,9);
end if;
when "11" => -- NTSC 720x480 60Hz
sprite_y_adjust <= to_unsigned(24,8);
vicii_ycounter_scale_minus_zero <= to_unsigned(2-1,4);
-- NTSC but with PAL max raster
vicii_max_raster <= pal_max_raster;
hsync_polarity_internal <= '1';
vsync_polarity_internal <= '0';
if vicii_ntsc /= fastio_wdata(7) then
vicii_first_raster <= to_unsigned(7,9);
end if;
when others => -- Default to NTSC 800x600 60Hz
sprite_y_adjust <= to_unsigned(24,8);
vicii_ycounter_scale_minus_zero <= to_unsigned(2-1,4);
hsync_polarity_internal <= '1';
vsync_polarity_internal <= '0';
if vicii_ntsc /= fastio_wdata(7) then
vicii_first_raster <= to_unsigned(7,9);
end if;
end case;
end if;
elsif register_number=112 then
-- @IO:GS $D070 NONE:VIC-IV palette bank selection
-- @IO:GS $D070.7-6 VIC-IV:MAPEDPAL palette bank mapped at $D100-$D3FF
palette_bank_fastio <= fastio_wdata(7 downto 6);
-- @IO:GS $D070.5-4 VIC-IV:BTPALSEL bitmap/text palette bank
palette_bank_chargen <= fastio_wdata(5 downto 4);
-- @IO:GS $D070.3-2 VIC-IV:SPRPALSEL sprite palette bank
palette_bank_sprites <= fastio_wdata(3 downto 2);
-- @IO:GS $D070.1-0 VIC-IV:ABTPALSEL VIC-IV bitmap/text palette bank (alternate palette)
palette_bank_chargen_alt <= fastio_wdata(1 downto 0);
elsif register_number=113 then -- $D3071
-- @IO:GS $D071 VIC-IV:BP16ENS VIC-IV 16-colour bitplane enable flags
bitplane_sixteen_colour_mode_flags <= fastio_wdata;
elsif register_number=114 then -- $D3072
-- @IO:GS $D072 VIC-IV:SPRYADJ Sprite Y position adjustment
sprite_y_adjust <= unsigned(fastio_wdata);
elsif register_number=115 then -- $D3073
-- @IO:GS $D073.0-3 VIC-IV:ALPHADELAY Alpha delay for compositor
reg_alpha_Delay <= unsigned(fastio_wdata(3 downto 0));
-- @IO:GS $D073.4-7 VIC-IV:RASTERHEIGHT physical rasters per VIC-II raster (1 to 16)
vicii_ycounter_scale_minus_zero(3 downto 0) <= unsigned(fastio_wdata(7 downto 4));
elsif register_number=116 then -- $D3074
-- @IO:GS $D074 VIC-IV:SPRENALPHA Sprite alpha-blend enable
sprite_alpha_blend_enables <= fastio_wdata;
elsif register_number=117 then
-- @IO:GS $D075 VIC-IV:SPRALPHAVAL Sprite alpha-blend value
sprite_alpha_blend_value <= unsigned(fastio_wdata);
elsif register_number=118 then
-- @IO:GS $D076 VIC-IV:SPRENV400 Sprite V400 enables
sprite_v400s <= fastio_wdata;
elsif register_number=119 then -- $D3077
-- @IO:GS $D077 VIC-IV:SPRYMSBS Sprite V400 Y position MSBs
sprite_v400_msbs <= fastio_wdata;
elsif register_number=120 then -- $D3078
-- @IO:GS $D078 VIC-IV:SPRYSMSBS Sprite V400 Y position super MSBs
sprite_v400_super_msbs <= fastio_wdata;
elsif register_number=121 then -- $D3079
-- @IO:GS $D079 VIC-IV:RASCMP Physical raster compare value to be used if FNRSTCMP is clear
vicii_raster_compare(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=122 then -- $D307A
-- @IO:GS $D07A.0-2 VIC-IV:RASCMP!MSB Raster compare value MSB
-- @IO:GS $D07A.3 VIC-IV:SPTR!CONT Continuously monitor sprite pointer, to allow changing sprite data source while a sprite is being drawn
-- @IO:GS $D07A.4 VIC-IV:CHARY16 Alternate char ROM bank on alternate raster lines in V200
-- @IO:GS $D07A.5 VIC-IV:NOBUGCOMPAT *DEPRECATED*, use HWERRATA - Disables VIC-III / C65 Bug Compatibility Mode if set
-- @IO:GS $D07A.6 VIC-IV:EXTIRQS Enable additional IRQ sources, e.g., raster X position.
-- @IO:GS $D07A.7 VIC-IV:FNRST!CMP Raster compare is in physical rasters if clear, or VIC-II rasters if set
irq_extras_enable <= fastio_wdata(6);
reg_char_y16 <= fastio_wdata(4);
sprite_continuous_pointer_monitoring <= fastio_wdata(3);
vicii_raster_compare(10 downto 8) <= unsigned(fastio_wdata(2 downto 0));
vicii_is_raster_source <= fastio_wdata(7);
prev_bug_compat_mode <= not fastio_wdata(5);
if fastio_wdata(5)=prev_bug_compat_mode then
if fastio_wdata(5)='1' then
-- Disable compatibility = enable errata
hw_errata_enable_toggle <= not hw_errata_enable_toggle;
else
hw_errata_disable_toggle <= not hw_errata_disable_toggle;
end if;
end if;
elsif register_number=123 then
-- @IO:GS $D07B VIC-IV:DISP!ROWS Number of text rows to display
display_row_count <= unsigned(fastio_wdata);
elsif register_number=124 then
-- @IO:GS $D07C.0-2 VIC-IV:BIT!PBANK Set which 128KB bank bitplanes
-- are fetched from.
bitplane_bank_select <= unsigned(fastio_wdata(2 downto 0));
dat_bitplane_bank <= unsigned(fastio_wdata(2 downto 0));
-- @IO:GS $D07C.3 VIC-IV:RESV @RESV
-- @IO:GS $D07C.4 VIC-IV:HSYNCP hsync polarity
hsync_polarity_internal <= fastio_wdata(4);
-- @IO:GS $D07C.5 VIC-IV:VSYNCP vsync polarity
vsync_polarity_internal <= fastio_wdata(5);
-- @IO:GS $D07C.6-7 VIC-IV:DEBUGC VIC-IV debug pixel select red(01), green(10) or blue(11) channel visible in $D07D
debug_channel_select <= fastio_wdata(7 downto 6);
elsif register_number=125 then
-- @IO:GS $D07D DEBUG:DEBUGX VIC-IV debug X position (LSB) (write only)
-- @IO:GS $D07D DEBUG:DEBUGOUT VIC-IV debug value read-back (read only)
debug_x(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=126 then
-- @IO:GS $D07E DEBUG:DEBUGY VIC-IV debug Y position (LSB)
debug_y(7 downto 0) <= unsigned(fastio_wdata);
elsif register_number=127 then
-- @IO:GS $D07F.0-3 DEBUG:DEBUGX VIC-IV debug X position (MSB)
-- @IO:GS $D07F.7 DEBUG:DEBUGOOF VIC-IV debug out-of-frame signal enable
debug_x(11 downto 8) <= unsigned(fastio_wdata(3 downto 0));
debug_x(13 downto 12) <= "00";
-- @IO:GS $D07F.4-7 DEBUG:DEBUGY VIC-IV debug Y position (MSB)
debug_y(11 downto 8) <= unsigned(fastio_wdata(7 downto 4));
elsif register_number<255 then
-- reserved register, FDC and RAM expansion controller
null;
elsif register_number>=256 and register_number<512 then
-- @IO:C65 $D100-$D1FF VIC-III:PALRED red palette values (reversed nybl order)
palette_fastio_address <= palette_bank_fastio & std_logic_vector(register_number(7 downto 0));
palette_we(3) <= '1';
elsif register_number>=512 and register_number<768 then
-- @IO:C65 $D200-$D2FF VIC-III:PALGREEN green palette values (reversed nybl order)
palette_fastio_address <= palette_bank_fastio & std_logic_vector(register_number(7 downto 0));
palette_we(2) <= '1';
elsif register_number>=768 and register_number<1024 then
-- @IO:C65 $D300-$D3FF VIC-III:PALBLUE blue palette values (reversed nybl order)
palette_fastio_address <= palette_bank_fastio & std_logic_vector(register_number(7 downto 0));
palette_we(1) <= '1';
else
null;
end if;
end if;
end if;
end process;
process(pixelclock,all_pause,reg_h640,ramaddress,this_screen_row_fetch_address,glyph_full_colour,
inborder,inborder_drive,inborder_drive2) is
variable indisplay : std_logic := '0';
variable card_bg_colour : unsigned(7 downto 0) := (others => '0');
variable card_fg_colour : unsigned(7 downto 0) := (others => '0');
variable long_address : unsigned(31 downto 0) := (others => '0');
variable next_glyph_number_temp : std_logic_vector(12 downto 0) := (others => '0');
variable next_glyph_colour_temp : std_logic_vector(7 downto 0) := (others => '0');
begin
if rising_edge(pixelclock) and all_pause='0' then
report "ycounter = $" & to_hstring(ycounter) & ", ycounter_driver = $" & to_hstring(ycounter_driver);
ycounter <= ycounter_driver;
vgared <= vgared_driver;
vgagreen <= vgagreen_driver;
vgablue <= vgablue_driver;
-- Capture pixel at prescribed position to support automated testing
-- and display red cross-hairs
if xcounter=debug_x xor ycounter=debug_y then
-- Draw cross-hairs at debug coordinates
vgared <= x"FF";
vgagreen <= x"00";
vgablue <= x"00";
end if;
if (xcounter=debug_x) and (ycounter=debug_y) then
debug_pixel_red <= vgared_driver;
debug_pixel_green <= vgagreen_driver;
debug_pixel_blue <= vgablue_driver;
end if;
sprite_data_offsets(sprite_number_for_data_rx) <= sprite_data_offset_rx;
-- Ask for the next one (8 sprites + 8 C65 bitplanes)
if sprite_number_counter = 15 then
sprite_number_counter <= 0;
sprite_number_for_data_tx <= 0;
else
sprite_number_counter <= sprite_number_counter + 1;
sprite_number_for_data_tx <= sprite_number_for_data_tx + 1;
end if;
pixel_x_640 <= safe_to_integer(xcounter);
pixel_x_800 <= safe_to_integer(xcounter);
pixel_y_scale_400 <= chargen_y_scale_400(3 downto 0);
pixel_y_scale_200 <= chargen_y_scale_200(3 downto 0);
-- But also export native X position, e.g., for touch panel interface to
-- match up with visual keyboard
-- XXX Why do we need these fudge factors to make everything line up?
-- Subtract 10 for video pipeline depth?
native_x_640 <= safe_to_integer(vicii_xcounter_640 - 10);
-- Subtract 34 for some reason?
native_y_200 <= safe_to_integer(vicii_ycounter - 34);
native_y_400 <= safe_to_integer(displayy);
--chardata_drive <= unsigned(chardata);
--paint_chardata <= chardata_drive;
paint_chardata <= unsigned(chardata);
ramdata_drive <= ramdata;
paint_ramdata <= ramdata_drive;
sprite_fetch_drive <= '0';
inborder_drive2 <= inborder_drive;
inborder_drive <= inborder;
-- Acknowledge IRQs after reading $D019
irq_raster <= irq_raster and (not ack_raster);
irq_rasterx <= irq_rasterx and (not ack_rasterx);
irq_lightpen <= irq_lightpen and (not ack_lightpen);
irq_collisionspritebitmap <= irq_collisionspritebitmap and (not ack_collisionspritebitmap);
irq_collisionspritesprite <= irq_collisionspritesprite and (not ack_collisionspritesprite);
-- Set IRQ line status to CPU
irq_drive <= not ((irq_raster and mask_raster)
or (irq_rasterx and mask_rasterx and irq_extras_enable)
or (irq_lightpen and mask_lightpen)
or (irq_collisionspritebitmap and mask_collisionspritebitmap)
or (irq_collisionspritesprite and mask_collisionspritesprite));
-- Add new sprite collision bits to the bitmap
case vicii_sprite_sprite_collision_map is
when "00000000" | "10000000" | "01000000" | "00100000" | "00010000" |
"00001000" | "00000100" | "00000010" | "00000001" =>
vicii_sprite_sprite_collisions <= vicii_sprite_sprite_collisions and (vicii_sprite_sprite_collisions'range => not(clear_collisionspritesprite));
when others =>
-- Sprite collision, so add it to the existing map
vicii_sprite_sprite_collisions
<= (vicii_sprite_sprite_collisions and (vicii_sprite_sprite_collisions'range => not(clear_collisionspritesprite))) or
(vicii_sprite_sprite_collision_map and (vicii_sprite_sprite_collision_map'range => not(postsprite_inborder)));
end case;
-- Sprite foreground collision is easier: always add it on.
vicii_sprite_bitmap_collisions
<= (vicii_sprite_bitmap_collisions and (vicii_sprite_bitmap_collisions'range => not(clear_collisionspritebitmap))) or
(vicii_sprite_bitmap_collision_map and (vicii_sprite_bitmap_collision_map'range => not(postsprite_inborder)));
-- Now check if we need to trigger an IRQ due to sprite collisions:
if vicii_sprite_sprite_collisions /= "00000000" then
irq_collisionspritesprite <= '1';
end if;
if vicii_sprite_bitmap_collisions /= "00000000" then
irq_collisionspritebitmap <= '1';
end if;
-- Detect lightpen event (must appear above irq_lightpen assignment above)
if touch_active='1' and xcounter_drive(11 downto 0) = touch_x and displayy = touch_y then
irq_lightpen <= '1';
lightpen_x_latch <= touch_x(11 downto 4);
lightpen_y_latch <= touch_y(9 downto 2);
end if;
-- reset masks IRQs immediately
if irq_drive = '0' then
irq <= '0';
else
irq <= 'H';
end if;
-- Hsync has trouble meeting timing, so I have spread out the control
-- over 3 cycles, including one pure drive cycle, which should hopefully
-- fix it once and for all.
xcounter_delayed <= xcounter;
if pixel_newframe_internal='1' then
-- C65/VIC-III style 1Hz blink attribute clock
viciii_blink_phase_counter <= viciii_blink_phase_counter + 1;
if viciii_blink_phase_counter = 30 then
viciii_blink_phase_counter <= 0;
viciii_blink_phase <= not viciii_blink_phase;
end if;
-- 4Hz 1581 drive LED blink clock
drive_blink_phase_counter <= drive_blink_phase_counter + 1;
if drive_blink_phase_counter = 15 then
drive_blink_phase_counter <= 0;
drive_blink_phase <= not drive_blink_phase;
end if;
end if;
indisplay :='1';
-- Make variably delayed xcounter signal, so that we can correct delay
-- for pipeline depth
external_pixel_strobe_log(0) <= external_pixel_strobe_in;
external_pixel_strobe_log(31 downto 1) <= external_pixel_strobe_log(30 downto 0);
if external_frame_x_zero_latched='0' and external_pixel_strobe_log(reg_xcounter_delay)='1' then
report "PIXEL xcounter_pipeline_delayed increased";
xcounter_pipeline_delayed <= xcounter_pipeline_delayed + 1;
elsif external_frame_x_zero_latched='1' then
xcounter_pipeline_delayed <= 0;
end if;
if external_frame_x_zero_latched='0' and external_pixel_strobe_log(0)='1' and vga_in_frame='1' then
raster_buffer_read_address(9 downto 0) <= raster_buffer_read_address_next(9 downto 0);
raster_buffer_read_address_sub <= raster_buffer_read_address_sub_next;
report "PIXEL pixel strobe edge";
xcounter <= xcounter + 1;
-- Allow H640 sprites to begin from far-left
if (xcounter = sprite_first_x) or (sprite_h640='1') then
sprite_x_counting <= '1';
end if;
if sprite_x_counting = '1' then
report "sprite_x_counting=1, vicii_xcounter_640 = " & to_hstring(vicii_xcounter_640);
vicii_xcounter_640 <= vicii_xcounter_640 + 1;
sprite_x_scale_toggle <= not sprite_x_scale_toggle;
if sprite_x_scale_toggle = '1' then
vicii_xcounter_320 <= vicii_xcounter_320 + 1;
end if;
end if;
end if;
if external_frame_x_zero_latched = '1' then
-- End of raster reached.
-- Bump raster number and start next raster.
report "XZERO: ycounter=" & integer'image(safe_to_integer(ycounter));
xcounter <= (others => '0');
sprite_x_counting <= '0';
sprite_x_scale_toggle <= '0';
-- Make delayed stopping of chargen rendering take effect
-- (this has to happen on the following raster, because we determine
-- end of screen when we pre-compute the next row address)
if last_external_frame_x_zero_latched = '0' then
if stop_chargen_raster_counter /= 0 then
stop_chargen_raster_counter <= stop_chargen_raster_counter - 1;
end if;
end if;
if stop_chargen_raster_counter = 1 then
before_y_chargen_start <= '1';
end if;
vicii_ycounter_scale <= vicii_ycounter_scale_minus_zero;
report "LEGACY vicii_ycounter_scale = " & integer'image(safe_to_integer(vicii_ycounter_scale))
& ", vicii_ycounter_max_phase = " & integer'image(safe_to_integer(vicii_ycounter_max_phase))
& ", text_mode=" & std_logic'image(text_mode)
& ", screen_ram_base=$" & to_hstring(screen_ram_base)
& ", character_set_base=$" & to_hstring(character_set_address)
& ", screen_ram_buffer_read_address=" & integer'image(safe_to_integer(screen_ram_buffer_read_address))
& ", first_card_of_row=" & integer'image(safe_to_integer(first_card_of_row))
& ", chargen_y=" & integer'image(safe_to_integer(chargen_y))
& ", chargen_y_sub = " & integer'image(safe_to_integer(chargen_y_sub))
;
vicii_xcounter_320 <= to_unsigned(0,9);
vicii_xcounter_640 <= to_unsigned(0,10);
chargen_active <= '0';
chargen_active_soon <= '0';
-- Make VIC-II triggered raster interrupts edge triggered, since one
-- emulated VIC-II raster is ~63*48 = ~3,000 cycles, and many C64
-- raster routines may finish in that time, and might get confused if
-- a raster interrupt gets retriggered too soon. This will also cause
-- some problems for software that really expects multiple interrupts
-- on the same raster line, but that should be really quite rare.
-- We could allow multiple triggerings per raster when CPU is at <= 3.5MHz,
-- and only edge trigger it when at full speed?
-- As we have a one raster line delay in display, we delay the raster
-- interrupt by one line also, so that it better matches what we see on
-- a VIC-II.
if enable_raster_delay='1' then
vicii_raster_compare_plus_one <= vicii_raster_compare + 1;
else
vicii_raster_compare_plus_one <= vicii_raster_compare;
end if;
if (xcounter_drive = viciv_rasterx_compare) then
irq_rasterx <= '1';
end if;
if (vicii_is_raster_source='1') and (vicii_ycounter = vicii_raster_compare_plus_one(8 downto 0)) and last_vicii_ycounter /= vicii_ycounter then
irq_raster <= '1';
end if;
last_vicii_ycounter <= vicii_ycounter;
-- Make VIC-IV raster interrupts edge triggered, as well, to avoid re-triggering
-- of the raster interrupt at the end of the raster line (eg. if the raster
-- interrupt has already been acknowledged before the raster line reaches the end).
-- Retriggering would happen once external_frame_x_zero_latched = '1' but ycounter
-- not yet updated (it will get updated two clock cycles later).
if (vicii_is_raster_source='0') and (ycounter = vicii_raster_compare_plus_one) and last_ycounter /= ycounter then
irq_raster <= '1';
end if;
last_ycounter <= ycounter;
if last_external_frame_x_zero_latched='0' then
-- ... update Y position, even during VSYNC, since frame timing is
-- now exact.
report "XZERO: incrementing ycounter from " & integer'image(safe_to_integer(ycounter));
ycounter_driver <= ycounter_driver + 1;
displaycolumn0 <= '1';
displayy <= displayy + 1;
if displayy(4)='1' then
displayline0 <= '0';
end if;
if vicii_ycounter_phase = vicii_ycounter_max_phase then
if safe_to_integer(vicii_ycounter) /= vicii_max_raster then
vicii_ycounter <= vicii_ycounter + 1;
-- Indicate fixed point on the frame
-- (used by CPU to time entry into freeze routine for proper synchronisation.
-- Also helps thumbnails to not have tears in them).
if vicii_ycounter = to_unsigned(255,9) then
viciv_frame_indicate <= '1';
else
viciv_frame_indicate <= '0';
end if;
-- We update V400 position in this case, bug also in the
-- alternate case below
vicii_ycounter_v400 <= vicii_ycounter_v400 + 1;
end if;
vicii_ycounter_continuous <= vicii_ycounter_continuous + 1;
if vicii_ycounter_max_phase = 0 then
-- Calculate raster number for sprites.
if vicii_ycounter = (safe_to_integer(vicii_max_raster) + 2 - safe_to_integer(sprite_y_adjust)) then
vicii_sprite_ycounter <= to_unsigned(0,9);
else
vicii_sprite_ycounter <= vicii_ycounter_continuous - 2 + safe_to_integer(sprite_y_adjust);
end if;
end if;
vicii_ycounter_phase <= (others => '0');
-- All visible rasters are now equal height
-- (we take up the slack using vertical_flyback fast raster stepping,
-- and allow arbitrary setting of first raster of the VGA frame).
vicii_ycounter_max_phase <= vicii_ycounter_scale;
else
-- In the middle of a VIC-II logical raster, so just increase phase.
vicii_ycounter_phase <= vicii_ycounter_phase + 1;
-- But also bump V400 raster if required
if safe_to_integer(vicii_ycounter_phase) = safe_to_integer(vicii_ycounter_max_phase(3 downto 1)) then
vicii_ycounter_v400 <= vicii_ycounter_v400 + 1;
end if;
-- Calculate raster number for sprites.
-- The -2 is an adjustment factor to make the sprites line up correctly
-- on the screen.
-- This is done on an "off" line, so that the sprites line up properly
if vicii_ycounter = (safe_to_integer(vicii_max_raster) + 2 - safe_to_integer(sprite_y_adjust)) then
vicii_sprite_ycounter <= to_unsigned(0,9);
else
vicii_sprite_ycounter <= vicii_ycounter_continuous - 2 + safe_to_integer(sprite_y_adjust);
end if;
end if;
end if;
end if;
-- If we got far along the last line to make it look real, and ...
last_external_frame_y_zero <= external_frame_y_zero;
if external_frame_y_zero = '0' and last_external_frame_y_zero='1' then
-- Start of next frame
report "Starting new frame. ycounter_driver <= 0";
ycounter_driver <= (others =>'0');
report "LEGACY: chargen_y_sub = 0, first_card_of_row = 0 due to start of frame";
chargen_y_sub <= (others => '0');
first_card_of_row <= (others => '0');
displayy <= (others => '0');
displayline0 <= '1';
indisplay := '0';
report "clearing indisplay because xcounter=0" severity note;
screen_row_address <= screen_ram_base(19 downto 0);
display_row_number <= to_unsigned(0,8);
-- Reset VIC-II raster counter to first raster for top of frame
-- (the preceeding rasters occur during vertical flyback, in case they
-- have interrupts triggered on them).
vicii_ycounter_phase <= to_unsigned(1,4);
vicii_ycounter <= vicii_first_raster;
vicii_ycounter_continuous <= vicii_first_raster;
vicii_ycounter_v400 <= (others =>'0');
vicii_ycounter_phase_v400 <= to_unsigned(1,4);
end if;
if xcounter<frame_h_front then
xfrontporch <= '1';
else
xfrontporch <= '0';
end if;
if external_frame_x_zero_latched='1' then
-- tell frame grabber about each new raster
pixel_newraster <= '1';
else
pixel_newraster <= '0';
end if;
-- Work out when the horizonal back porch starts.
-- The edge is used to trigger drawing of the next raster into the raster
-- buffer.
-- We actually want to trigger this as early as possible, so that sprite
-- fetching doesn't run over into the next raster line.
-- 30MHz pixel clock @ 50Hz display means we will catch up 3.3 pixels
-- per pixel, so we can't start before (display_width - (display_width/3.3)).
if xcounter=0 then
report "stopping drawing at start of next raster";
chargen_active <= '0';
chargen_active_soon <= '0';
raster_buffer_read_address(10) <= raster_buffer_half_toggle;
raster_buffer_max_write_address_prev <= raster_buffer_max_write_address_hold;
report "setting raster_buffer_max_write_address_prev to $" & to_hstring(raster_buffer_max_write_address_hold);
end if;
if raster_buffer_read_address_next(9 downto 0) > raster_buffer_max_write_address_prev then
report "stopping character generator due to buffer exhaustion"
severity note;
chargen_active <= '0';
chargen_active_soon <= '0';
end if;
-- Work out where in the current character we seem to be
-- (and allowing for smooth scrolling etc during drawing of the frame)
if reg_v400='1' then
if y_chargen_start > displayy then
pixels_since_last_char <= "000";
else
pixels_since_last_char <= to_unsigned(safe_to_integer(displayy) - safe_to_integer(y_chargen_start),3) + 1;
end if;
else
if y_chargen_start > displayy(11 downto 1) then
pixels_since_last_char <= "000";
else
pixels_since_last_char <= to_unsigned(safe_to_integer(displayy(11 downto 1)) - safe_to_integer(y_chargen_start),3)
-- Magic fudge factor to get everything
-- lining up correctly
+ to_unsigned(safe_to_integer(y_chargen_start(3 downto 1)) + 1,3);
end if;
end if;
last_was_fetch_start <= is_fetch_start;
is_fetch_start <= '0';
if raster_buffer_double_line='0' or ycounter(0)='0' then
if no_raster_buffer_delay='0' then
if xcounter=(safe_to_integer(frame_h_front)+display_fetch_start) then
is_fetch_start <= '1';
end if;
else
if xcounter=(safe_to_integer(frame_h_front)+display_fetch_start) then
is_fetch_start <= '1';
end if;
end if;
end if;
if is_fetch_start='1' and last_was_fetch_start='0' then
-- Start of filling raster buffer.
-- We don't need to double-buffer, as we start filling from the back
-- porch of the previous line, hundreds of cycles before the start of
-- the next line of display.
report "RASTER FETCH: start of fetch in preparation for the next raster";
report "ZEROing screen_ram_buffer_read_address" severity note;
screen_ram_buffer_read_address <= to_unsigned(0,10);
-- Some house keeping first:
-- Reset write address in raster buffer
-- Set write address to all 1's, so that it wraps to zero at the start
raster_buffer_write_address(9 downto 0) <= (others => '1');
-- Make sure we read and write to opposite halves of the raster buffer
raster_buffer_write_address(10) <= raster_buffer_half_toggle xor no_raster_buffer_delay;
raster_buffer_half_toggle <= not raster_buffer_half_toggle;
raster_buffer_max_write_address_hold <= raster_buffer_max_write_address;
report "setting raster_buffer_max_write_address_hold to $" & to_hstring(raster_buffer_max_write_address);
-- Reset glyph Y offset each raster line
glyph_y_offset <= 0;
-- Reset glyph using nve y offset
glyph_nve_y_offset <= '0';
-- Hold chargen_y for entire fetch, so that we don't get glitching when
-- chargen_y increases part way through resulting in characters on
-- right of display shifting up one physical pixel.
chargen_y_hold <= chargen_y;
if chargen_y_hold = chargen_y then
charrow_repeated <= '1';
else
charrow_repeated <= '0';
end if;
-- Work out colour ram address
report "COLOURRAM: Setting colourramaddress via first_card_of_row."
& " text_mode=" & std_logic'image(text_mode)
& ", sixteenbit_charset=" & std_logic'image(sixteenbit_charset);
colourramaddress <= colour_ram_base + first_card_of_row;
-- Work out the screen ram address. We only need to re-fetch screen
-- RAM if first_card_of_row is different to last time.
prev_first_card_of_row <= first_card_of_row;
-- Set all signals for both eventuality, since none are shared between
-- the two paths. This helps keep the logic shallow.
-- Delay application of screen_ram_base address changes by one raster line
-- so match behaviour of VIC-II
if (text_mode='0') and (sixteenbit_charset='1') then
-- bitmap mode in sixteen bit char mode uses 2 screen RAM bytes per
-- card, but not two bitmap bytes, so we have to increment double
screen_row_current_address
<= to_unsigned(safe_to_integer(screen_ram_base(19 downto 0))
+ safe_to_integer(first_card_of_row) + safe_to_integer(first_card_of_row),20);
else
screen_row_current_address
<= to_unsigned(safe_to_integer(screen_ram_base(19 downto 0))
+ safe_to_integer(first_card_of_row),20);
end if;
card_of_row <= (others =>'0');
screen_ram_buffer_write_address <= to_unsigned(0,10);
short_line <= '0';
report "ZEROing screen_ram_buffer_write_address" severity note;
-- Finally decide which way we should go
if safe_to_integer(first_card_of_row) /= safe_to_integer(prev_first_card_of_row) then
raster_fetch_state <= FetchScreenRamLine;
-- From Section 3.5 of http://www.zimmers.net/cbmpics/cbm/c64/vic-ii.txt
-- (but has problems for some reason)
if (blank = '0') and ((vertical_border='0') or justbefore_y_chargen_start='1') and (vicii_ycounter<248) and (vicii_ycounter>=40) then
badline_toggle_internal <= not badline_toggle_internal;
badline_toggle <= not badline_toggle_internal;
report "BADLINE @ y = " & integer'image(safe_to_integer(displayy)) severity note;
report "BADLINE first_card_of_row = %" & to_string(std_logic_vector(first_card_of_row)) severity note;
report "BADLINE prev_first_card_of_row = %" & to_string(std_logic_vector(prev_first_card_of_row)) severity note;
else
report "BADLINE in vertical border suppressed @ y = " & integer'image(safe_to_integer(displayy)) severity note;
end if;
else
report "noBADLINE" severity note;
raster_fetch_state <= FetchFirstCharacter;
end if;
-- Now check if we have tipped over from one logical pixel row to another.
chargen_y <= chargen_y_next;
if chargen_y_sub=chargen_y_scale then
chargen_y_next <= chargen_y_next + 1;
if chargen_y_scale /= 0 then
if chargen_y_next = "111" then
report "bumping chargen_y to " & integer'image(safe_to_integer(chargen_y)) severity note;
bump_screen_row_address<='1';
end if;
if pixels_since_last_char = "111" then
chargen_y_next <= "000";
end if;
else
if chargen_y_next = "111" then
report "LEGACY: Bumping screen row address one raster early for V400";
bump_screen_row_address<='1';
end if;
if pixels_since_last_char = "110" then
chargen_y_next <= "000";
end if;
end if;
if (chargen_y_scale=x"02") and (chargen_y(0)='1') then
chargen_y_sub <= "00001";
else
report "LEGACY: chargen_y_sub = 0 due increment of chargen_y";
chargen_y_sub <= (others => '0');
end if;
else
report "LEGACY: chargen_y_sub incremented";
chargen_y_sub <= chargen_y_sub + 1;
end if;
if bump_screen_row_address='1' then
bump_screen_row_address <= '0';
-- Compute the address for the screen row.
if (text_mode='0') and (sixteenbit_charset='1') then
-- 16bit charset mode + bitmap mode = 2 bytes screen memory per card,
-- so that we can pick foreground and background colours from full
-- 256-colour palette.
screen_row_address <= screen_ram_base(19 downto 0) + first_card_of_row;
else
screen_row_address <= screen_ram_base(19 downto 0) + first_card_of_row;
end if;
if before_y_chargen_start='0' then
-- Increment card number every "bad line"
report "LEGACY: Advancing first_card_of_row due to end of character";
first_card_of_row <= to_unsigned(safe_to_integer(first_card_of_row) + row_advance,16);
display_row_number <= display_row_number + 1;
if display_row_number = display_row_count then
-- Stop chargen on next raster
stop_chargen_raster_counter <= stop_chargen_delay;
end if;
else
report "LEGACY: NOT advancing first_card_of_row due to end of character (before_y_chargen_start=1)";
end if;
end if;
end if;
if xcounter<(safe_to_integer(frame_h_front)+display_width) then
xbackporch <= '0';
xbackporch_edge <= '0';
else
xbackporch <= '1';
xbackporch_edge <= not xbackporch;
end if;
-- Work out if the border is active
if displayy=border_y_bottom then
vertical_border <= '1';
end if;
if displayy=border_y_top then
vertical_border <= '0';
end if;
if xcounter<border_x_left or xcounter>=border_x_right or
vertical_border='1' then
inborder<='1';
viciv_flyback <= '1';
else
inborder<=blank;
viciv_flyback <= '0';
end if;
if vga_in_frame = '0' then
indisplay := '0';
report "clearing indisplay because of horizontal porch" severity note;
end if;
-- Calculate vertical flyback and related signals
if ycounter=frame_v_front then
vert_in_frame <= '1';
elsif ycounter=0 then
-- Start of vertical flyback
indisplay := '0';
report "clearing indisplay because of vertical porch";
vert_in_frame <= '0';
-- Send a 1 cycle pulse at the end of each frame for
-- streaming display module to synchronise on.
if vert_in_frame = '1' then
pixel_frame_toggle <= not pixel_frame_toggle;
pixel_newframe <= '1';
pixel_newframe_internal <= '1';
else
pixel_newframe <= '0';
pixel_newframe_internal <= '0';
end if;
end if;
-- Generate pixel clock based on x640 clock
last_vicii_xcounter_640 <= vicii_xcounter_640;
if vicii_xcounter_640 /= last_vicii_xcounter_640 then
lcd_pixel_strobe <= indisplay;
report "lcd_pixel_strobe = " & std_logic'image(indisplay);
else
lcd_pixel_strobe <= '0';
report "lcd_pixel_strobe = 0";
end if;
report "chargen_active=" & std_logic'image(chargen_active)
& ", xcounter = " & to_string(std_logic_vector(xcounter))
& ", x_chargen_start = " & to_string(std_logic_vector(x_chargen_start)) severity note;
if xcounter=border_x_right then
-- Stop character generator as soon as we hit the right border
-- so that we can switch to fetching sprite data for the next raster.
report "Masking chargen_active based on xcounter<border_x_right" severity note;
chargen_active <= '0';
chargen_active_soon <= '0';
end if;
x_chargen_start_minus1 <= x_chargen_start - 1;
if xcounter = x_chargen_start_minus1 then
-- trigger next card at start of chargen row
chargen_x <= (others => '0');
report "reset chargen_x" severity note;
end if;
if xcounter = x_chargen_start then
-- Gets masked to 0 below if displayy is above y_chargen_start
chargen_active <= '1';
report "Setting chargen_active based on xcounter = x_chargen_start" severity note;
chargen_active_soon <= '0';
end if;
y_chargen_start_minus_one <= y_chargen_start-1;
if displayy = (y_chargen_start_minus_one) then
justbefore_y_chargen_start <= '1';
else
justbefore_y_chargen_start <= '0';
end if;
if displayy = "000000000000" then
before_y_chargen_start <= '1';
elsif displayy = y_chargen_start then
before_y_chargen_start <= '0';
end if;
-- Allow y_chargen_start to be shifted down mid-frame to allow
-- multiple character displays per screen, e.g., for fixed vs scrolling.
if displayy < y_chargen_start_minus_one then
before_y_chargen_start <= '1';
end if;
if before_y_chargen_start = '1' and justbefore_y_chargen_start='0' then
-- We have to reset the chargen Y value pipeline.
-- So chargen_y goes to zero, but we then need to make sure we don't
-- accidentally double print the top line of pixels, so we pre-advance
-- chargen_y_sub or chargen_y_next as appropriate.
chargen_y <= "000";
if chargen_y_scale = 0 then
chargen_y_next <= "001";
chargen_y_sub <= "00000";
else
chargen_y_next <= "000";
chargen_y_sub <= "00001";
end if;
if chargen_y_sub /= 0 then
report "LEGACY: Reseting chargen_y_sub";
end if;
chargen_active <= '0';
chargen_active_soon <= '0';
-- Force badline so that moving chargen down results in fresh loading
-- of the first line of text.
prev_first_card_of_row <= (others => '1');
report "Masking chargen_active based on displayy<y_chargen_start" severity note;
end if;
if xcounter(5)='1' and xcounter(4)='1' then
displaycolumn0 <= '0';
end if;
if xcounter = 0 then
report "ycounter = " & integer'image(safe_to_integer(ycounter))
& ", before_y_chargen_start = " & std_logic'image(before_y_chargen_start)
& ", chargen_y = " & integer'image(safe_to_integer(chargen_y))
& ", chargen_y_sub = " & integer'image(safe_to_integer(chargen_y_sub))
& ", chargen_active = " & std_logic'image(chargen_active)
;
end if;
if short_line='1' then
row_advance <= short_line_length;
else
row_advance <= safe_to_integer(virtual_row_width);
end if;
viciv_outofframe <= (not indisplay_t3);
-- if indisplay_t3='1' then
if inborder='1' or (bitplane_mode='1' and viciv_bitplane_chargen_on='0') then
pixel_colour <= border_colour;
pixel_alpha <= x"FF";
report "VICIV: Drawing border" severity note;
elsif chargen_active='0' then
pixel_colour <= screen_colour;
report "VICIV: no character pixel data as chargen_active=0" severity note;
else
-- Otherwise read pixel data from raster buffer
if raster_buffer_read_address(9 downto 0) = to_unsigned(0,10) then
report "LEGACY: Painting pixels from raster buffer";
end if;
report "VICIV: raster buffer reading next from = $" & to_hstring(raster_buffer_read_address)
& "/$" & to_hstring(raster_buffer_max_write_address_prev)
& ", pixel_colour = $" & to_hstring(raster_buffer_read_data(7 downto 0))
& ", pixel_alpha = $" & to_hstring(raster_buffer_read_data(16 downto 9))
& ", pixel_is_foreground = " & std_logic'image(raster_buffer_read_data(8))
severity note;
pixel_colour <= raster_buffer_read_data(7 downto 0);
pixel_alpha <= raster_buffer_read_data(16 downto 9);
-- 18th bit indicates to use primary or alternate palette
pixel_alt_palette <= raster_buffer_read_data(17);
-- 9th bit indicates foreground for sprite collission handling
pixel_is_background <= not raster_buffer_read_data(8);
pixel_is_foreground <= raster_buffer_read_data(8);
end if;
-- Make delayed versions of card number and x position so that we have time
-- to fetch character row data.
chargen_x_t1 <= chargen_x;
chargen_x_t2 <= chargen_x_t1;
chargen_x_t3 <= chargen_x_t2;
charrow_t1 <= charrow;
charrow_t2 <= charrow_t1;
card_number_t1 <= card_number(7 downto 0);
card_number_t2 <= card_number_t1;
card_number_t3 <= card_number_t2;
indisplay_t1 <= indisplay;
indisplay_t2 <= indisplay_t1;
indisplay_t3 <= indisplay_t2;
-- We use a drive stage for these lines to preserve CPU timing.
debug_cycles_to_next_card_drive <= debug_cycles_to_next_card;
debug_chargen_active_drive <= debug_chargen_active;
debug_chargen_active_soon_drive <= debug_chargen_active_soon;
debug_raster_fetch_state_drive <= debug_raster_fetch_state;
debug_paint_fsm_state_drive <= debug_paint_fsm_state;
debug_charrow_drive <= debug_charrow;
debug_charaddress_drive <= debug_charaddress;
debug_character_data_from_rom_drive <= debug_character_data_from_rom;
debug_screen_ram_buffer_address_drive <= debug_screen_ram_buffer_address;
debug_raster_buffer_read_address_drive <= debug_raster_buffer_read_address;
debug_raster_buffer_write_address_drive <= debug_raster_buffer_write_address;
-- Actually, we use two drive stages since the video timing is so pernickety.
-- The 2nd drive stage is driven by the cpuclock. Search for _drive2 to
-- find it.
if xcounter=debug_x and ycounter=debug_y then
debug_cycles_to_next_card <= cycles_to_next_card;
debug_chargen_active <= chargen_active;
debug_chargen_active_soon <= chargen_active_soon;
debug_raster_fetch_state <= raster_fetch_state;
debug_paint_fsm_state <= paint_fsm_state;
debug_charrow <= charrow;
-- debug_charaddress <= charaddress;
debug_character_data_from_rom <= character_data_from_rom;
debug_screen_ram_buffer_address <= screen_ram_buffer_read_address;
debug_raster_buffer_read_address <= raster_buffer_read_address(7 downto 0);
debug_raster_buffer_write_address <= raster_buffer_write_address(7 downto 0);
end if;
-- Pixels have a two cycle pipeline to help keep timing contraints:
report "PIXEL (" & integer'image(safe_to_integer(xcounter)) & "," & integer'image(safe_to_integer(displayy)) & ") : colour =\ $"
& to_hstring(postsprite_pixel_colour)
& ", RGBA = $" &to_hstring(palette_rdata)
& ", alpha = $" & to_hstring(postsprite_alpha_value)
& ", vga_in_frame = " & std_logic'image(vga_in_frame)
& ", external_pixel_strobe = " & std_logic'image(external_pixel_strobe_in)
severity note;
-- 1. From pixel colour lookup RGB
-- Feed pixel into sprite pipeline
report "Feeding pixel+alpha to pipeline: pixel_colour=$" & to_hstring(pixel_colour)
& ", pixel_alpha=$" & to_hstring(pixel_alpha);
chargen_pixel_colour <= pixel_colour;
chargen_alpha_value <= pixel_alpha;
pixel_is_foreground_in <= pixel_is_foreground;
pixel_is_background_in <= pixel_is_background;
--report "SPRITE: pre_pixel_colour = $" & to_hstring(pixel_colour)
-- & ", postsprite_pixel_colour = $" & to_hstring(postsprite_pixel_colour);
-- One pixel delay required for alternate palette selection
postsprite_alternate_palette_delayed <= postsprite_alternate_palette;
-- Use palette bank 3 for "palette ROM" colours (C64 default colours
-- should be placed there for C65 compatibility).
if postsprite_pixel_colour(7 downto 4) = x"0" and reg_palrom='0' then
-- Get pixel colour (which may be foreground or background)
palette_address <= "11" & std_logic_vector(postsprite_pixel_colour);
-- Get the colour of the background for doing the alpha blending
alias_palette_address <= "11" & std_logic_vector(paint_background);
if pixel_is_sprite='0' or sprite_alpha_blend_enables(postsprite_sprite_number)='0' then
alpha_blend_alpha <= postsprite_alpha_value;
else
alpha_blend_alpha <= sprite_alpha_blend_value;
end if;
else
palette_address(7 downto 0) <= std_logic_vector(postsprite_pixel_colour);
alias_palette_address(7 downto 0) <= std_logic_vector(paint_background);
if pixel_is_sprite='0' then
if postsprite_alternate_palette_delayed='1' then
palette_address(9 downto 8) <= palette_bank_chargen_alt;
alias_palette_address(9 downto 8) <= palette_bank_chargen_alt;
else
palette_address(9 downto 8) <= palette_bank_chargen;
alias_palette_address(9 downto 8) <= palette_bank_chargen_alt;
end if;
alpha_blend_alpha <= postsprite_alpha_value;
else
-- If the pixel is a sprite pixel, then apply the sprite alpha value.
-- XXX The video pipeline currently doesn't tell us WHICH sprite the
-- pixel belongs to, and we need to know this to be able to decide if
-- we should alpha blend the sprite pixel to whatever is behind it.
-- XXX We should blend to the non-sprite palette, so that sprites can
-- have their own colours, but still fade into any background colour.
palette_address(9 downto 8) <= palette_bank_sprites;
alias_palette_address(9 downto 8) <= palette_bank_sprites;
if sprite_alpha_blend_enables(postsprite_sprite_number)='0' then
alpha_blend_alpha <= postsprite_alpha_value;
else
alpha_blend_alpha <= sprite_alpha_blend_value;
end if;
end if;
end if;
if xray_mode='1' then
-- Debug mode enabled using switch 1 to show whether we think pixels
-- are foreground, background, sprite and/or border.
palette_address(9 downto 6) <= (others => '0');
palette_address(5) <= postsprite_pixel_colour(0);
palette_address(4) <= paint_background(0);
-- background was always set due to bug with passing in foreground flag
-- to background flag in sprite module.
-- sprite + text = $7 (foreground, sprites and background!)
-- text = $E (foreground and background, and not alpha sprite pixel)
-- sprite white fg (=+$20) on blue bg (= no +$10) = $21, as expected
if pixel_is_sprite='0' or sprite_alpha_blend_enables(postsprite_sprite_number)='0' then
palette_address(3) <= '1';
else
palette_address(3) <= postsprite_inborder;
end if;
palette_address(2) <= pixel_is_foreground_out;
palette_address(1) <= pixel_is_background_out;
palette_address(0) <= pixel_is_sprite;
end if;
-- VIC-III palette RGB values have only the high bits in the low nybl, and
-- the high-nybl is reserved.
-- VIC-IV puts the low nybl in those reserved high-nybl bits
vga_buffer_red(7 downto 4) <= unsigned(palette_rdata(27 downto 24));
vga_buffer_red(3 downto 0) <= unsigned(palette_rdata(31 downto 28));
vga_buffer_green(7 downto 4) <= unsigned(palette_rdata(19 downto 16));
vga_buffer_green(3 downto 0) <= unsigned(palette_rdata(23 downto 20));
vga_buffer_blue(7 downto 4) <= unsigned(palette_rdata(11 downto 8));
vga_buffer_blue(3 downto 0) <= unsigned(palette_rdata(15 downto 12));
--vga_buffer_red <= unsigned(postsprite_pixel_colour);
--vga_buffer_green <= unsigned(postsprite_pixel_colour);
--vga_buffer_blue <= unsigned(postsprite_pixel_colour);
--vga_buffer_red <= unsigned(postsprite_pixel_colour);
--vga_buffer_green <= unsigned(postsprite_pixel_colour);
--vga_buffer_blue <= unsigned(postsprite_pixel_colour);
-- The nybls have not been switched around for the alpha palette, so we
-- have to do that here
composite_bg_red(7 downto 4) <= unsigned(alias_palette_rdata(27 downto 24));
composite_bg_red(3 downto 0) <= unsigned(alias_palette_rdata(31 downto 28));
composite_bg_green(7 downto 4) <= unsigned(alias_palette_rdata(19 downto 16));
composite_bg_green(3 downto 0) <= unsigned(alias_palette_rdata(23 downto 20));
composite_bg_blue(7 downto 4) <= unsigned(alias_palette_rdata(11 downto 8));
composite_bg_blue(3 downto 0) <= unsigned(alias_palette_rdata(15 downto 12));
composite_red <= vga_buffer_red;
composite_green <= vga_buffer_green;
composite_blue <= vga_buffer_blue;
report "Palette read address = $" & to_hstring(palette_address)
& ", alpha palette read address = $" & to_hstring(alias_palette_address)
& ", rdata=$" & to_hstring(palette_rdata)
& ", alias rdata=$" & to_hstring(alias_palette_rdata);
report "compositing background "
& "R=$" & to_hstring(alias_palette_rdata(31 downto 24))
& ", G=$" & to_hstring(alias_palette_rdata(23 downto 16))
& ", B=$" & to_hstring(alias_palette_rdata(15 downto 8))
&" with foreground "
& "R=$" & to_hstring(vga_buffer_red)
& ", G=$" & to_hstring(vga_buffer_green)
& ", B=$" & to_hstring(vga_buffer_blue)
& ", alpha=$" & to_hstring(raster_buffer_read_data(16 downto 9));
report "alpha composited"
& " red=$" & to_hstring(composited_red(9 downto 2))
& ", green=$" & to_hstring(composited_green(9 downto 2))
& ", blue=$" & to_hstring(composited_blue(9 downto 2));
if compositer_enable='1' then
vga_buffer2_red <= unsigned(composited_red(9 downto 2));
vga_buffer2_green <= unsigned(composited_green(9 downto 2));
vga_buffer2_blue <= unsigned(composited_blue(9 downto 2));
else
vga_buffer2_red <= vga_buffer_red;
vga_buffer2_green <= vga_buffer_green;
vga_buffer2_blue <= vga_buffer_blue;
end if;
vga_buffer3_red <= vga_buffer2_red;
vga_buffer3_green <= vga_buffer2_green;
vga_buffer3_blue <= vga_buffer2_blue;
vga_buffer4_red <= vga_buffer3_red;
vga_buffer4_green <= vga_buffer3_green;
vga_buffer4_blue <= vga_buffer3_blue;
vga_buffer5_red <= vga_buffer4_red;
vga_buffer5_green <= vga_buffer4_green;
vga_buffer5_blue <= vga_buffer4_blue;
vga_filtered_red <= to_unsigned(safe_to_integer(vga_buffer5_red)
+safe_to_integer(vga_buffer4_red)
+safe_to_integer(vga_buffer3_red)
+safe_to_integer(vga_buffer2_red),10);
vga_filtered_green <= to_unsigned(safe_to_integer(vga_buffer5_green)
+safe_to_integer(vga_buffer4_green)
+safe_to_integer(vga_buffer3_green)
+safe_to_integer(vga_buffer2_green),10);
vga_filtered_blue <= to_unsigned(safe_to_integer(vga_buffer5_blue)
+safe_to_integer(vga_buffer4_blue)
+safe_to_integer(vga_buffer3_blue)
+safe_to_integer(vga_buffer2_blue),10);
if horizontal_filter='0' or reg_h1280='1' then
vga_palin_red <= vga_buffer3_red;
vga_palin_green <= vga_buffer3_green;
vga_palin_blue <= vga_buffer3_blue;
else
vga_palin_red <= vga_filtered_red(9 downto 2);
vga_palin_green <= vga_filtered_green(9 downto 2);
vga_palin_blue <= vga_filtered_blue(9 downto 2);
end if;
if pal_simulate='1' and reg_h1280 = '0' and (reg_v400 = '0' or (reg_v400 = '1' and raster_buffer_double_line = '1')) then
vga_out_red <= vga_palout_red;
vga_out_green <= vga_palout_green;
vga_out_blue <= vga_palout_blue;
else
vga_out_red <= vga_palin_red;
vga_out_green <= vga_palin_green;
vga_out_blue <= vga_palin_blue;
end if;
-- Also use pixel colour to produce RLE compressed video stream for
-- pushing over ethernet on ff10::6565:6565:6565 IPv6 transient
-- multi-cast address or via serial console. However we do it, we first
-- need to compress the video as much as possible, and to do that, we need
-- the pixel stream.
-- Announce each raster line. Can also be used to identify start of frame.
if xcounter=safe_to_integer(display_width) then
report "FRAMEPACKER: end of raster announcement";
pixel_newraster <= '1';
pixel_strobe_out <= '0';
pixel_y <= displayy;
else
-- output pixels as packed RGB instead of palette colours
-- (this 8bpp format is what VNC uses anyway, so there is no functional
-- loss of colour resolution).
pixel_stream_out(7 downto 5) <= vga_buffer3_red(7 downto 5);
pixel_stream_out(4 downto 2) <= vga_buffer3_green(7 downto 5);
pixel_stream_out(1 downto 0) <= vga_buffer3_blue(7 downto 6);
-- And also output full 24bit RGB, that the new frame packer uses
pixel_red_out <= vga_buffer3_red;
pixel_green_out <= vga_buffer3_green;
pixel_blue_out <= vga_buffer3_blue;
xcounter_last <= xcounter;
if xcounter /= xcounter_last then
-- XXX pixel_strobe_in should be fed through the pipeline and delayed
-- to match, so that the correct pixels get latched.
report "pixel = " & std_logic'image(indisplay)
& ", xcounter = " & integer'image(safe_to_integer(xcounter));
pixel_strobe_out <= indisplay;
pixel_x_out <= safe_to_integer(xcounter);
else
pixel_strobe_out <= '0';
end if;
pixel_newraster <= '0';
end if;
-- 2. From RGB, push out to pins (also draw border)
if (displayline0 ='1') and (displaycolumn0='1')
and (((led='1') and (drive_blink_phase='1'))
or (motor='1')) then
report "drawing drive led OSD" severity note;
drive_led_out <= '1';
vgared_driver <= x"FF";
vgagreen_driver <= x"00";
vgablue_driver <= x"00";
else
drive_led_out <= '0';
if show_render_activity='1' then
vgared_driver <= (others => render_activity(0));
vgagreen_driver <= (others => render_activity(1));
vgablue_driver <= (others => render_activity(2));
else
vgared_driver <= vga_out_red(7 downto 0);
vgagreen_driver <= vga_out_green(7 downto 0);
vgablue_driver <= vga_out_blue(7 downto 0);
end if;
end if;
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
-- Character/bitmap data preparation
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--------------------------------------------------------------------------
-- Do chipram read based on fetch scheduled in previous cycle
this_ramaccess_is_screen_row_fetch <= next_ramaccess_is_screen_row_fetch;
this_ramaccess_is_glyph_data_fetch <= next_ramaccess_is_glyph_data_fetch;
this_ramaccess_is_sprite_data_fetch <= next_ramaccess_is_sprite_data_fetch;
this_ramaccess_screen_row_buffer_address
<= next_ramaccess_screen_row_buffer_address;
this_screen_row_fetch_address <= next_screen_row_fetch_address;
last_ramaccess_is_screen_row_fetch <= this_ramaccess_is_screen_row_fetch;
last_ramaccess_is_glyph_data_fetch <= this_ramaccess_is_glyph_data_fetch;
last_ramaccess_is_sprite_data_fetch <= this_ramaccess_is_sprite_data_fetch;
last_ramaccess_screen_row_buffer_address
<= this_ramaccess_screen_row_buffer_address;
last_screen_row_fetch_address <= this_screen_row_fetch_address;
final_ramdata <= ramdata;
final_ramaccess_is_screen_row_fetch <= last_ramaccess_is_screen_row_fetch;
final_ramaccess_is_glyph_data_fetch <= last_ramaccess_is_glyph_data_fetch;
final_ramaccess_is_sprite_data_fetch <= last_ramaccess_is_sprite_data_fetch;
final_ramaccess_screen_row_buffer_address
<= last_ramaccess_screen_row_buffer_address;
final_screen_row_fetch_address <= last_screen_row_fetch_address;
if final_ramaccess_is_screen_row_fetch='1' then
report "buffering screen ram byte $" & to_hstring(final_ramdata) & " to address $" & to_hstring(to_unsigned(safe_to_integer(final_ramaccess_screen_row_buffer_address),16));
end if;
screen_ram_buffer_write <= final_ramaccess_is_screen_row_fetch;
screen_ram_buffer_write_address <= final_ramaccess_screen_row_buffer_address;
screen_ram_buffer_din <= final_ramdata;
-- Collect last token for processing
screen_line_last_token(15 downto 8) <= final_ramdata;
screen_line_last_token(7 downto 0) <= screen_line_last_token(15 downto 8);
if raster_fetch_state /= Idle or paint_fsm_state /= Idle then
report "raster_fetch_state=" & vic_chargen_fsm'image(raster_fetch_state) & ", "
& "paint_fsm_state=" & vic_paint_fsm'image(paint_fsm_state)
& ", rb_w_addr=$" & to_hstring(raster_buffer_write_address) severity note;
end if;
-- Pre-calculate some expressions to flatten logic in critical path
-- Note we use prev_first_card_of_row, so that we don't show the last pixel
-- row from the next char card row down the screen.
if reg_h640='1' then
bitmap_glyph_data_address
<= (character_set_address(19 downto 14)&"00000000000000")
+ (safe_to_integer(screen_ram_buffer_read_address)+safe_to_integer(prev_first_card_of_row))*8+safe_to_integer(chargen_y_hold);
else
bitmap_glyph_data_address
<= (character_set_address(19 downto 13)&"0000000000000")
+ (safe_to_integer(screen_ram_buffer_read_address)+safe_to_integer(prev_first_card_of_row))*8+safe_to_integer(chargen_y_hold);
end if;
if xcounter = 0 then
report "LEGACY: bitmap_glyph_data_address = $"
& to_hstring(
to_unsigned(safe_to_integer(character_set_address(19 downto 13))*8192
+ safe_to_integer(screen_ram_buffer_read_address)
+safe_to_integer(first_card_of_row)*8
+safe_to_integer(chargen_y_hold)
,17)
);
end if;
display_row_width_minus1 <= display_row_width - 1;
ramaddress <= next_ramaddress;
report "raster_fetch_state = " & vic_chargen_fsm'image(raster_fetch_state);
case raster_fetch_state is
when Idle => null;
-- Show what we are doing in debug display mode
render_activity <= "000";
when FetchScreenRamLine =>
-- Make sure that painting is not in progress
if bitplane_mode='1' then
paint_fsm_state <= Idle;
raster_fetch_state <= EndOfCharGen;
elsif paint_ready='1' then
-- Set FSM state so that no painting occurs, and so that we
-- continue to fetch the screen row. Note that here we just
-- schedule the memory reads. The data is written elsewhere. This
-- helps to simplify the logic in terms of number of states in the
-- machine, as well as for accepting the data when it has been read.
paint_fsm_state <= Idle;
raster_fetch_state <= FetchScreenRamLine2;
-- Show what we are doing in debug display mode
render_activity <= "001";
-- Reset screen row (bad line) state
character_number <= to_unsigned(1,11);
end_of_row_16 <= '0'; end_of_row <= '0';
report "COLOURRAM: Setting colourramaddress via first_card_of_row."
& " text_mode=" & std_logic'image(text_mode)
& ", sixteenbit_charset=" & std_logic'image(sixteenbit_charset);
colourramaddress <= to_unsigned(safe_to_integer(colour_ram_base) + safe_to_integer(first_card_of_row),16);
-- Now ask for the first byte. We indicate all details of this
-- read so that it can be committed by the receiving side of the logic.
next_ramaccess_is_screen_row_fetch <= '1';
next_ramaccess_is_glyph_data_fetch <= '0';
next_ramaccess_is_sprite_data_fetch <= '0';
next_ramaccess_screen_row_buffer_address <= to_unsigned(0,10);
next_screen_row_fetch_address <= screen_row_current_address;
-- Set pipeline delay countdown for investigating the 16-bit tokens
-- to see if they indicate programmatic instructions, rather than
-- ordinary characte data.
badlineprog_countdown <= 5;
report "BADLINE, colour_ram_base=$" & to_hstring(colour_ram_base) severity note;
report "LEGACY: Badline fetch: "
& "screen_row_current_address = $" & to_hstring(screen_row_current_address)
;
end if;
when FetchScreenRamLine2 =>
-- Ask for the next byte. We indicate all details of this
-- read so that it can be committed by the receiving side of the logic.
-- Otherwise, if we are at the end of the row, then stop.
-- XXX check the last stored token to see if it is a GOTO, GOSUB or RETURN.
-- If it is, rewind, and redirect accordingly.
-- Part of the challenge here is that the bytes here are delayed by
-- several cycles, so we have to take that into account.
if sixteenbit_charset='1' then
if badlineprog_countdown = 0 then
report "BADLINEPROG: last_token=$" & to_hstring(screen_line_last_token);
if next_token_is_goto='1' then
-- Set screen RAM fetch to the value of this token (shifted
-- left one bit).
-- XXX goto tokens can only point to first 128KB of RAM.
next_screen_row_fetch_address(19 downto 17) <= "000";
next_screen_row_fetch_address(16 downto 1) <= screen_line_last_token;
next_screen_row_fetch_address(0) <= '0';
-- Flush screen row buffer fetch pipeline while waiting for
-- branch to complete
badlineprog_inhibit_screen_row_buffer_write_counter <= 4;
-- Clear next token is branch flag
next_token_is_goto <= '0';
else
case screen_line_last_token is
when x"FFFF" =>
-- End of line / RETURN token
-- If nothing on the stack, this is the last token to fetch.
null;
when x"FFFE" =>
-- GOTO: Next token is address to goto (shifted left one bit)
null;
when x"FFFD" =>
-- GOSUB: Next token is address to goto (shifted left one bit)
-- (Same as GOTO, except that we push the write offset to be
-- retrieved on return.)
null;
when others =>
null;
end case;
end if;
-- We need two bytes before we have next token, so set count down
badlineprog_countdown <= 1;
else
badlineprog_countdown <= badlineprog_countdown - 1;
end if;
end if;
-- Is this the last character in the row?
-- (Only used when screen lines have only one character?)
if character_number = display_row_width_minus1&'1' then
end_of_row_16 <= '1';
else
end_of_row_16 <= '0';
end if;
if character_number = '0'&display_row_width_minus1 then
end_of_row <= '1';
else
end_of_row <= '0';
end if;
-- Work out if we need to fetch any more
if (sixteenbit_charset='1' and end_of_row_16='1')
or (sixteenbit_charset='0' and end_of_row='1') then
-- All done, move to actual row fetch
raster_fetch_state <= FetchFirstCharacter;
next_ramaccess_is_screen_row_fetch <= '0';
next_ramaccess_is_glyph_data_fetch <= '0';
next_ramaccess_is_sprite_data_fetch <= '0';
else
-- More to fetch, so keep scheduling the reads
if screenline_return_stack_count = 0 then
-- Only advance fetched character counter if we are not in a
-- GOSUB in the screen row data.
character_number <= character_number + 1;
end if;
next_ramaccess_is_screen_row_fetch <= '1';
report "Scheduling read of $" & to_hstring(next_screen_row_fetch_address)
& " for screen row read.";
next_ramaccess_is_glyph_data_fetch <= '0';
next_ramaccess_is_sprite_data_fetch <= '0';
if next_token_is_goto='0' then
next_ramaccess_screen_row_buffer_address <= next_ramaccess_screen_row_buffer_address + 1;
next_screen_row_fetch_address <= next_screen_row_fetch_address + 1;
end if;
end if;
when FetchFirstCharacter =>
-- Show what we are doing in debug display mode
render_activity <= "010";
next_ramaccess_is_screen_row_fetch <= '0';
next_ramaccess_is_glyph_data_fetch <= '0';
next_ramaccess_is_sprite_data_fetch <= '0';
-- By default glyphs do paint the background when required.
-- (This can be turned off for the rest of a line by using a tab-stop
-- token).
glyph_paint_background <= '1';
-- And don't invert palettes by default
glyph_alternate_palette_invert <= '0';
-- By default, characters are drawn in the foreground.
-- If force_chars_background is set, then chars are forced into the background.
-- If force_chars_foreground is set, then chars are forced into the foreground
-- (ignoreing if a particular colour bit would normally be required
-- to achieve this).
force_chars_foreground <= '1';
force_chars_background <= '0';
-- By default, draw all pixel rows of each character
screenline_draw_mask <= (others => '1');
report "DRAWMASK: Reset drawmask to $ff";
report "ZEROing screen_ram_buffer_read_address" severity note;
screen_ram_buffer_read_address <= to_unsigned(0,10);
character_number <= (others => '0');
card_of_row <= (others => '0');
if bitplane_mode='0' or viciv_bitplane_chargen_on='1' then
raster_fetch_state <= FetchNextCharacter;
else
raster_fetch_state <= EndOfCharGen;
end if;
when FetchNextCharacter =>
-- Fetch next character
-- All we can expect here is that character_number is correctly set.
report "screen_ram byte read from buffer as $" & to_hstring(screen_ram_buffer_dout) severity note;
-- XXX: Timing to be fixed.
-- (Ideally we would take only 8 cycles to fetch a character so that
-- we use as little raster time as possible, especially for true 1920
-- pixel modes. However, for now, the emphasis is on making it work.
-- In particular, we should pipeline reading of the next character
-- number and resolving relevant information about it with the fetching
-- of the data for the current character. That would basically fix it.)
-- Based on either the card number (for bitmap modes) or
-- character_number (for text modes), work out the address where the
-- data lives.
-- Work out exactly what mode we are in so that we can be a bit more
-- efficient in the next cycle
if screen_ram_buffer_read_address = to_unsigned(0,10) then
report "LEGACY: Char/bitmap data fetch: "
& "chargen_y_hold = $" & to_hstring(chargen_y_hold)
& ", chargen_y = $" & to_hstring(chargen_y)
& ", chargen_y_next = $" & to_hstring(chargen_y_next)
;
end if;
if text_mode='1' then
-- Read 8 or 16 bit screen RAM data for character number information
-- (the address was put on the bus for us already).
-- Handle extended background colour mode here if required.
glyph_number(12 downto 8) <= "00000";
glyph_number(5 downto 0) <= screen_ram_buffer_dout(5 downto 0);
if extended_background_mode='1' then
background_colour_select <= screen_ram_buffer_dout(7 downto 6);
else
background_colour_select <= "00";
glyph_number(7 downto 6) <= screen_ram_buffer_dout(7 downto 6);
end if;
else
-- Read 8 or 16 bits of colour information for bitmap modes.
-- In 16 bit charset mode we allow 8 bits for fore and back-ground
-- colours.
if sixteenbit_charset='1' then
bitmap_colour_foreground <= screen_ram_buffer_dout;
else
bitmap_colour_foreground <= x"0" & screen_ram_buffer_dout(7 downto 4);
bitmap_colour_background <= x"0" & screen_ram_buffer_dout(3 downto 0);
end if;
end if;
-- calculate data address for bitmap mode in case we need it
-- bitmap area is always on an 8KB boundary
glyph_data_address <= bitmap_glyph_data_address;
report "bitmap srba="& integer'image(safe_to_integer(screen_ram_buffer_read_address))
& ", fcor="& integer'image(safe_to_integer(first_card_of_row))
severity note;
screen_ram_buffer_read_address <= screen_ram_buffer_read_address + 1;
report "INCREMENTing screen_ram_buffer_read_address to " & integer'image(safe_to_integer(screen_ram_buffer_read_address)+1) severity note;
-- Clear 16-bit character attributes in case we are reading 8-bits only.
glyph_flip_horizontal <= '0';
glyph_flip_vertical <= '0';
glyph_with_alpha <= '0';
glyph_width_deduct <= to_unsigned(0,4);
glyph_goto <= '0';
glyph_4bit <= '0';
screen_ram_is_ff <= '0';
screen_ram_high_is_ff <= '0';
if sixteenbit_charset='1' then
if screen_ram_buffer_dout = x"ff" then
screen_ram_is_ff <= '1';
end if;
raster_fetch_state <= FetchCharHighByte;
else
-- 8 bit character set / colour info mode
glyph_full_colour <= fullcolour_8bitchars;
if text_mode='1' then
raster_fetch_state <= FetchTextCell;
else
raster_fetch_state <= FetchBitmapCell;
end if;
end if;
when FetchCharHighByte =>
-- In 16-bit character mode we also need to read the 2nd colour byte,
-- which are doing now, so we need to advance colourramaddress ready
-- to read the low colour byte of the next character.
report "COLOURRAM: Incrementing colourramaddress";
colourramaddress <= colourramaddress + 1;
report "reading high colour byte";
-- Work out if character is full colour (ignored for bitmap mode but
-- calculated outside of if test to flatten logic).
if screen_ram_buffer_dout(4 downto 0) = "00000" then
glyph_full_colour <= fullcolour_8bitchars;
else
glyph_full_colour <= fullcolour_extendedchars;
end if;
if text_mode='1' then
-- We only allow 8192 characters in extended mode.
-- The spare bits are used to provide some (hopefully useful)
-- extended attributes.
glyph_number(12 downto 8) <= screen_ram_buffer_dout(4 downto 0);
glyph_width_deduct(2 downto 0) <= screen_ram_buffer_dout(7 downto 5);
glyph_width_deduct(3) <= '0';
if screen_ram_buffer_dout = x"ff" then
screen_ram_high_is_ff <= '1';
end if;
-- First colour RAM byte has vertical controls
glyph_flip_vertical <= colourramdata(7);
glyph_flip_horizontal <= colourramdata(6);
glyph_with_alpha <= colourramdata(5);
-- bit 4 indicates glyph number is actually a GOTO pixel number
-- (allows over-rendering and skipping)
glyph_goto <= colourramdata(4);
-- Enables chars to be 16x8, with 4 bits each using
-- full-colour painting pipeline
glyph_4bit <= colourramdata(3);
report "DRAWMASK: Reading glyph_4bit from bit 3 of $" & to_hstring(colourramdata);
if colourramdata(3)='1' then
glyph_full_colour <= '1';
end if;
-- Because the glyphs are 16 pixels wide, we need to have an extra
-- bit for width trimming
glyph_width_deduct(3) <= colourramdata(2);
-- XXX colour ram bits 0 - 1 of byte 1 were for trimming top or bottom
-- of rows of glyphs, but have since been reclaimed.
raster_fetch_State <= FetchTextCell;
else
bitmap_colour_background <= screen_ram_buffer_dout;
raster_fetch_state <= FetchBitmapCell;
end if;
-- calculate data address for bitmap mode in case we need it
-- bitmap area is always on an 8KB boundary
glyph_data_address <= bitmap_glyph_data_address;
report "bitmap srba="& integer'image(safe_to_integer(screen_ram_buffer_read_address))
& ", fcor="& integer'image(safe_to_integer(first_card_of_row))
severity note;
screen_ram_buffer_read_address <= screen_ram_buffer_read_address + 1;
report "INCREMENTing screen_ram_buffer_read_address to " & integer'image(safe_to_integer(screen_ram_buffer_read_address)+1) severity note;
when FetchBitmapCell =>
report "LEGACY: from bitmap layout, we get glyph_data_address = $" & to_hstring("000"&glyph_data_address) severity note;
raster_fetch_state <= FetchBitmapData;
when FetchTextCell =>
if screen_ram_is_ff='1' and screen_ram_high_is_ff='1' then
-- 16-bit Character is $FFFF, which is end of line marker.
-- So remember that this line is short, and don't add the virtual
-- row width, and abort drawing this line.
short_line <= '1';
short_line_length <= safe_to_integer(screen_ram_buffer_read_address);
end if;
report "LEGACY: from screen_ram we get glyph_number = $" & to_hstring(to_unsigned(safe_to_integer(glyph_number),16)) severity note;
-- We now know the character number, and whether it is full-colour or
-- normal, and whether we are flipping in either axis, and so can
-- work out the address to fetch data from.
if glyph_with_alpha='1' then
report "glyph is alpha blended";
end if;
-- Work out if we are drawing this line of this char
draw_mask_blank <= not screenline_draw_mask(to_integer(chargen_y_hold));
report "DRAWMASK: Y = " & integer'image(to_integer(chargen_y_hold))
& ": Setting draw_mask_blank to " & std_logic'image(not screenline_draw_mask(to_integer(chargen_y_hold)))
& ", glyph_4bit = " & std_logic'image(glyph_4bit)
& ", screenline_draw_mask = $" & to_hstring(screenline_draw_mask);
if glyph_full_colour='1' then
report "glyph is full colour";
-- Full colour glyphs come from 64*(glyph_number) in RAM, never
-- from character ROM. As we only have 2^16 positions, the glyphs
-- must be in only the first 512KB of chipram.
glyph_data_address(19) <= '0';
-- if vertical flip bit is set fetch the char data with 7 - chargen_y
if glyph_flip_vertical='1' then
-- Allow setting an offset in the glyph address for easier
-- free vertical positioning of RRB soft-sprites
if glyph_nve_y_offset='1' then
-- -ve offset visibly moves the char data down the screen
glyph_data_address(18 downto 3) <= (glyph_number(12 downto 0) & not chargen_y_hold) - glyph_y_offset;
else
-- +ve offset visibly moves the char data up the screen
glyph_data_address(18 downto 3) <= (glyph_number(12 downto 0) & not chargen_y_hold) + glyph_y_offset;
end if;
else
-- Allow setting an offset in the glyph address for easier
-- free vertical positioning of RRB soft-sprites
if glyph_nve_y_offset='1' then
-- -ve offset visibly moves the char data down the screen
glyph_data_address(18 downto 3) <= (glyph_number(12 downto 0) & chargen_y_hold) - glyph_y_offset;
else
-- +ve offset visibly moves the char data up the screen
glyph_data_address(18 downto 3) <= (glyph_number(12 downto 0) & chargen_y_hold) + glyph_y_offset;
end if;
end if;
if glyph_flip_horizontal='1' then
glyph_data_address(2 downto 0) <= "111";
else
glyph_data_address(2 downto 0) <= "000";
end if;
character_data_from_rom <= '0';
else
-- Normal character glyph fetched relative to character_set_address.
-- Again, we take into account if we are flipping vertically.
if glyph_flip_vertical='0' then
glyph_data_address
<= character_set_address(19 downto 0)
+ safe_to_integer(glyph_number)*8+safe_to_integer(chargen_y_hold);
else
glyph_data_address
<= character_set_address(19 downto 0)
+ safe_to_integer(glyph_number)*8+7-safe_to_integer(chargen_y_hold);
end if;
-- Mark as possibly coming from ROM
character_data_from_rom <= '1';
end if;
raster_fetch_state <= FetchTextCellColourAndSource;
when FetchBitmapData =>
-- Show what we are doing in debug display mode
render_activity <= "011";
if character_data_from_rom = '1' then
if glyph_data_address(19 downto 12) = "0000"&x"1"
or glyph_data_address(19 downto 12) = "0000"&x"9" then
report "reading from rom: glyph_data_address=$" & to_hstring(glyph_data_address(15 downto 0))
& "chargen_y_hold=" & to_string(std_logic_vector(chargen_y_hold)) severity note;
character_data_from_rom <= '1';
else
character_data_from_rom <= '0';
end if;
end if;
-- Schedule next colour ram byte
report "COLOURRAM: Incrementing colourramaddress";
colourramaddress <= colourramaddress + 1;
if viciii_extended_attributes='1' or glyph_full_colour='1' then
-- 8-bit colour RAM in VIC-III/IV mode for bitmap mode, or for
-- full-colour text mode
glyph_colour_drive <= colourramdata;
else
-- 16 colours only in VIC-II mode
glyph_colour_drive(7 downto 4) <= x"0";
glyph_colour_drive(3 downto 0) <= colourramdata(3 downto 0);
end if;
glyph_visible_drive <= glyph_visible;
glyph_reverse_drive <= glyph_reverse;
glyph_underline_drive <= glyph_underline;
glyph_bold_drive <= glyph_bold;
raster_fetch_state <= PaintMemWait;
when FetchTextCellColourAndSource =>
-- Finally determine whether source is from RAM or CHARROM
if character_data_from_rom = '1' then
if glyph_data_address(19 downto 12) = "0000"&x"1"
or glyph_data_address(19 downto 12) = "0000"&x"9" then
report "reading from rom: glyph_data_address=$" & to_hstring(glyph_data_address(15 downto 0))
& "chargen_y=" & to_string(std_logic_vector(chargen_y_hold)) severity note;
character_data_from_rom <= '1';
else
character_data_from_rom <= '0';
end if;
end if;
-- Record colour and attribute information from colour RAM
-- XXX We do this even in bitmap mode!
if glyph_full_colour='1' and viciii_extended_attributes='0' then
glyph_colour_drive <= colourramdata;
else
glyph_colour_drive(7 downto 4) <= "0000";
glyph_colour_drive(3 downto 0) <= colourramdata(3 downto 0);
end if;
glyph_bold_drive <= '0';
glyph_underline_drive <= '0';
glyph_reverse_drive <= '0';
glyph_visible_drive <= '1';
glyph_blink_drive <= '0';
report "DRAWMASK: goto=" & std_logic'image(glyph_goto);
if glyph_goto='1' then
-- Also hold the 2nd colour RAM byte for use as the draw mask,
-- if its a GOTOX token with the appropriate bit set
screenline_draw_mask_drive <= colourramdata;
report "DRAWMASK: Loading screenline_draw_mask_drive with $" & to_hstring(colourramdata)
& ", glyph_4bit = " & std_logic'image(glyph_4bit);
end if;
-- Get bold + reverse combination, even if not in VIC-III extended attribute
-- mode, so that we can check for it in GOTOX tokens.
glyph_bold_and_reverse <= colourramdata(5) and colourramdata(6);
report "Reading high-byte of colour RAM (value $" & to_hstring(colourramdata)&")";
if multicolour_mode='1' then
-- Multicolour + full colour mode + 16-bit char mode = simple 256 colour foreground
-- colour selection from 2nd byte of colour RAM data
glyph_colour_drive(7 downto 4) <= colourramdata(7 downto 4);
else
if viciii_extended_attributes='1' then
-- VIC-III character attributes
if colourramdata(4)='1' then
-- Blinking glyph
glyph_blink_drive <= '1';
if colourramdata(5)='1'
or colourramdata(6)='1'
or colourramdata(7)='1' then
-- Blinking attributes
if viciii_blink_phase='1' then
glyph_reverse_drive <= colourramdata(5);
glyph_bold_drive <= colourramdata(6);
glyph_colour_drive(4) <= colourramdata(6);
if chargen_y_hold="111" then
glyph_underline_drive <= colourramdata(7);
end if;
end if;
else
-- Just plain blinking character
glyph_visible_drive <= viciii_blink_phase;
end if;
else
-- Non-blinking attributes
glyph_visible_drive <= '1';
glyph_reverse_drive <= colourramdata(5);
glyph_bold_drive <= colourramdata(6);
glyph_colour_drive(4) <= colourramdata(6);
if chargen_y_hold="111" then
glyph_underline_drive <= colourramdata(7);
end if;
end if;
end if;
end if;
-- Schedule next colour ram byte
report "COLOURRAM: Incrementing colourramaddress";
colourramaddress <= colourramaddress + 1;
raster_fetch_state <= PaintMemWait;
when PaintMemWait =>
-- This is the time that the 2nd colour byte will be available if we
-- are in 16-bit text mode, so copy out the value.
-- Allow for 2 cycle delay to get data in paint_ramdata
-- In this cycle chardata and ramdata will have the requested value
glyph_visible <= glyph_visible_drive;
glyph_reverse <= glyph_reverse_drive;
glyph_underline <= glyph_underline_drive;
glyph_bold <= glyph_bold_drive;
glyph_colour_drive2 <= glyph_colour_drive;
raster_fetch_state <= PaintMemWait2;
when PaintMemWait2 =>
glyph_colour <= glyph_colour_drive2;
if glyph_4bit='0' then
glyph_width <= 8 - safe_to_integer(glyph_width_deduct(2 downto 0));
else
glyph_width <= 16 - safe_to_integer(glyph_width_deduct(3 downto 0));
end if;
if glyph_full_colour = '1' then
if glyphs_from_hyperram='0' or (not hyper_installed) then
-- Fetch full-colour glyph data from chip ram
if glyph_flip_horizontal = '0' then
glyph_data_address(2 downto 0) <= glyph_data_address(2 downto 0) + 1;
else
glyph_data_address(2 downto 0) <= glyph_data_address(2 downto 0) - 1;
end if;
full_colour_fetch_count <= 0;
raster_fetch_state <= PaintFullColourFetch;
else
-- Fetch glyph data from ATTIC/CELLAR ram (hyperram)
report "HYPERRAM: Request for $" & to_hstring(glyph_data_address(18 downto 3)&"000")
& " dispatched.";
full_colour_fetch_count <= 0;
hyper_addr_drive(18 downto 3) <= glyph_data_address(18 downto 3);
hyper_request_toggle_drive <= not last_hyper_request_toggle;
last_hyper_request_toggle <= not last_hyper_request_toggle;
raster_fetch_state <= PaintFullColourHyperRAMFetch;
end if;
else
raster_fetch_state <= PaintMemWait3;
end if;
when PaintFullColourHyperRAMFetch =>
-- Read data from dedicated hyperram interface (a bit like the VRAM
-- that was originally planned for the Amiga Ranger chipset that was
-- never released.
if hyper_data_strobe='1' then
report "VIC: Receiving hyperram byte $" & to_hstring(hyper_data)
& ", full_colour_fetch_count = " & integer'image(full_colour_fetch_count);
if glyph_flip_horizontal='0' then
if glyph_visible='0' or draw_mask_blank='1' then
full_colour_data(63 downto 56) <= "00000000";
elsif glyph_underline='1' then
full_colour_data(63 downto 56) <= "11111111";
elsif glyph_reverse='1' and glyph_bold='0' then
full_colour_data(63 downto 56) <= hyper_data xor "11111111";
else
full_colour_data(63 downto 56) <= hyper_data;
end if;
full_colour_data(55 downto 0) <= full_colour_data(63 downto 8);
else
if glyph_visible='0' or draw_mask_blank='1' then
full_colour_data(7 downto 0) <= "00000000";
elsif glyph_underline='1' then
full_colour_data(7 downto 0) <= "11111111";
elsif glyph_reverse='1' and glyph_bold='0' then
full_colour_data(7 downto 0) <= hyper_data xor "11111111";
else
full_colour_data(7 downto 0) <= hyper_data;
end if;
full_colour_data(63 downto 8) <= full_colour_data(55 downto 0);
end if;
if full_colour_fetch_count < 7 then
raster_fetch_state <= PaintFullColourHyperRAMFetch;
full_colour_fetch_count <= full_colour_fetch_count + 1;
else
report "VIC: Received all bytes from HyperRAM. Resuming";
raster_fetch_state <= PaintMemWait3;
end if;
end if;
when PaintFullColourFetch =>
-- Show what we are doing in debug display mode
render_activity <= "100";
-- Read and store the 8 bytes of data we need for a full-colour character
report "LEGACY: glyph reading full-colour pixel value $" & to_hstring(ramdata);
if glyph_4bit='0' or glyph_flip_horizontal='0' then
-- Don't fly byte nybl order
full_colour_data(63 downto 56) <= ramdata;
else
-- Do flip byte nybl order
full_colour_data(63 downto 60) <= ramdata(3 downto 0);
full_colour_data(59 downto 56) <= ramdata(7 downto 4);
end if;
full_colour_data(55 downto 0) <= full_colour_data(63 downto 8);
if glyph_flip_horizontal = '0' then
glyph_data_address(2 downto 0) <= glyph_data_address(2 downto 0) + 1;
else
glyph_data_address(2 downto 0) <= glyph_data_address(2 downto 0) - 1;
end if;
if glyph_visible='0' or draw_mask_blank='1' then
full_colour_data(63 downto 56) <= "00000000";
end if;
if glyph_reverse='1' and glyph_bold='0' then
if glyph_4bit='0' or glyph_flip_horizontal='0' then
-- Don't flip byte nybl order
full_colour_data(63 downto 56) <= ramdata xor "11111111";
else
-- Do flip byte nybl order
full_colour_data(63 downto 60) <= ramdata(3 downto 0) xor "1111";
full_colour_data(59 downto 56) <= ramdata(7 downto 4) xor "1111";
end if;
end if;
if glyph_underline='1' then
full_colour_data(63 downto 56) <= "11111111";
end if;
if full_colour_fetch_count < 7 then
full_colour_fetch_count <= full_colour_fetch_count + 1;
raster_fetch_state <= PaintFullColourFetch;
else
raster_fetch_state <= PaintMemWait3;
end if;
when PaintMemWait3 =>
-- In this cycle paint_chardata and and paint_ramdata should have the
-- requested value
-- Abort if we have already drawn enough characters.
character_number <= character_number + 1;
-- We are counting the number characters, not the number of bytes, so
-- no need multiply row width by two for 16-bit character mode
-- if character_number = virtual_row_width_minus1(7 downto 0)&'0' then
if character_number(10 downto 0) = display_row_width_minus1 then
end_of_row_16 <= '1';
else
end_of_row_16 <= '0';
end if;
if character_number = '0'&display_row_width_minus1 then
end_of_row <= '1';
else
end_of_row <= '0';
end if;
if (end_of_row = '1') or (short_line='1') then
raster_fetch_state <= EndOfChargen;
else
raster_fetch_state <= PaintDispatch;
end if;
when PaintDispatch =>
-- Dispatch this card for painting.
-- Hold from dispatching if painting the previous card is not yet finished.
if paint_ready='1' then
paint_from_charrom <= character_data_from_rom;
report "character rom address set to $" & to_hstring(glyph_data_address(11 downto 0)) severity note;
-- Tell painter whether to flip horizontally or not.
paint_flip_horizontal <= glyph_flip_horizontal;
paint_glyph_width <= glyph_width;
paint_blink <= glyph_blink;
paint_glyph_4bit <= glyph_4bit;
paint_with_alpha <= glyph_with_alpha;
paint_alternate_palette <= glyph_reverse and glyph_bold;
if glyph_goto='1' then
report "DRAWMASK: PAINTING: is GOTOX";
-- Glyph is tab-stop glyph
-- Set screen ram buffer write address to 10 bit
-- offset indicated by glyph number bits
raster_buffer_write_address(9 downto 0) <= glyph_number(9 downto 0) - 1;
if glyph_4bit='1' then
screenline_draw_mask <= screenline_draw_mask_drive;
report "DRAWMASK: PAINTING: Setting screenline_draw_mask to $" & to_hstring(screenline_draw_mask_drive);
else
screenline_draw_mask <= (others => '1');
report "DRAWMASK: PAINTING: Ignoring drawmask. Using $ff (glyph_4bit not set)";
end if;
-- Allow setting of the glyph y offset in GOTO tokens
glyph_y_offset <= to_integer(glyph_width_deduct(2 downto 0));
-- Allow setting of y offset to be -ve instead of the default +pve
glyph_nve_y_offset <= glyph_number(12);
-- Also note whether the glyph painting should now not paint
-- background pixels, to allow masked over writing
glyph_paint_background <= not glyph_flip_vertical;
-- Allow bold + reverse on a GOTOX token to switch
-- primary/alternate palette selection for all chars that follow
glyph_alternate_palette_invert <= glyph_bold_and_reverse;
-- Also allow forcing of the following characters to be
-- background or foreground
force_chars_foreground <= glyph_width_deduct(3);
force_chars_background <= glyph_flip_horizontal;
-- ... and don't paint anything, because it is just
-- a tab stop.
elsif glyph_full_colour='1' then
-- Now work out exactly how we are painting
-- Paint full-colour glyph
report "LEGACY: Dispatching to PaintFullColour due to glyph_full_colour = 1";
-- We set background colour to screen colour in full-colour mode
-- for transparent pixels, and for alpha blending of anti-aliased
-- text. We do also support ECM mode.
case background_colour_select is
when "00" => paint_background <= screen_colour;
when "01" => paint_background <= multi1_colour;
when "10" => paint_background <= multi2_colour;
when "11" => paint_background <= multi3_colour;
when others => paint_background <= screen_colour;
end case;
-- For alpha-blended pixels, we need to make sure that we set
-- paint_foreground from glyph_colour, which allows us to have
-- 32 colours of anti-aliased text (using VIC-III bold attribute
-- to provide the 5th bit), as well as the option of reversed
-- text, which should invert the alpha-values).
paint_foreground <= glyph_colour;
paint_fsm_state <= PaintFullColour;
else
report "LEGACY: Dispatching normal due to glyph_full_colour = 0"
& ", paint_ready=" & std_logic'image(paint_ready);
if multicolour_mode='0' and extended_background_mode='0' then
-- Mono mode
if text_mode='1' then
paint_foreground <= glyph_colour;
paint_background <= screen_colour;
else
paint_foreground <= bitmap_colour_foreground;
paint_background <= bitmap_colour_background;
end if;
paint_fsm_state <= PaintMono;
elsif multicolour_mode='1' then
-- Multicolour mode
paint_background <= screen_colour;
if text_mode='1' then
if extended_background_mode='1' then
-- Illegal video mode that shows all black
paint_background <= x"00";
paint_mc1 <= x"00";
paint_mc2 <= x"00";
paint_foreground <= x"00";
else
if fullcolour_mcm='1' then
-- multi-colour text mode with full-colour VIC III/IV feature
-- See #571 for more discussion on this
paint_foreground <= glyph_colour;
else
-- multi-colour text mode masks bit 3 of the foreground
-- colour to select whether the character is multi-colour or
-- not.
paint_foreground <= "00000"&glyph_colour(2 downto 0);
end if;
paint_mc1 <= multi2_colour;
paint_mc2 <= multi1_colour;
end if;
else
if extended_background_mode='1' then
-- Illegal video mode that shows all black
paint_background <= x"00";
paint_mc1 <= x"00";
paint_mc2 <= x"00";
paint_foreground <= x"00";
else
paint_mc2 <= bitmap_colour_foreground;
paint_mc1 <= bitmap_colour_background;
paint_foreground <= glyph_colour;
end if;
end if;
if text_mode='1' and glyph_colour(3)='0' then
-- Multi-colour text mode only applies to colours 8-15,
-- so draw this glyph in mono
paint_fsm_state <= PaintMono;
else
-- Really do low-res multi-colour
paint_fsm_state <= PaintMultiColour;
end if;
elsif extended_background_mode='1' then
-- ECM (extended colour mode)
if text_mode='1' then
paint_foreground <= glyph_colour;
case background_colour_select is
when "00" => paint_background <= screen_colour;
when "01" => paint_background <= multi1_colour;
when "10" => paint_background <= multi2_colour;
when "11" => paint_background <= multi3_colour;
when others => paint_background <= screen_colour;
end case;
else
-- ECM + bitmap mode is illegal
paint_foreground <= x"00";
paint_background <= x"00";
end if;
paint_fsm_state <= PaintMono;
end if;
end if;
-- Fetch next character
raster_fetch_state <= FetchNextCharacter;
end if;
when EndOfChargen =>
-- Idle the painter, and then start drawing VIC-II sprites
if paint_ready='1' then
paint_fsm_state <= Idle;
end if;
if paint_fsm_state = Idle then
report "SPRITE: begin data fetch for raster";
raster_fetch_state <= SpritePointerFetch;
sprite_fetch_sprite_number <= 0;
sprite_fetch_byte_number <= 0;
end if;
when SpritePointerFetch =>
-- Show what we are doing in debug display mode
render_activity <= "101";
sprite_pointer_address(19 downto 17) <= "000";
sprite_datavalid <= '0';
if sprite_fetch_sprite_number = 16 or (sprite_fetch_sprite_number = 8 and bitplane_mode = '0') then
-- Done fetching sprites
raster_fetch_state <= Idle;
elsif sprite_fetch_sprite_number < 8 then
-- Fetch sprites
max_sprite_fetch_byte_number <= 7;
if vicii_sprite_pointer_address(23)='0' then
-- Normal 8-bit sprite pointers
sprite_pointer_address(19 downto 3) <= vicii_sprite_pointer_address(19 downto 3);
sprite_pointer_address(2 downto 0) <= to_unsigned(sprite_fetch_sprite_number,3);
report "SPRITE: will fetch pointer value from $" &
to_hstring(vicii_sprite_pointer_address(19 downto 0) + sprite_fetch_sprite_number);
else
-- 16-bit sprite pointers, allowing sprites to be sourced from
-- anywhere in first 64K x 64 = 4MB of chip RAM (of which we
-- currently have only 128KB :)
sprite_pointer_address(19 downto 4) <= vicii_sprite_pointer_address(19 downto 4);
sprite_pointer_address(3 downto 1) <= to_unsigned(sprite_fetch_sprite_number,3);
sprite_pointer_address(0) <= '0';
report "SPRITE: will fetch pointer LSB from $" &
to_hstring(vicii_sprite_pointer_address(19 downto 0) + sprite_fetch_sprite_number*2);
end if;
raster_fetch_state <= SpritePointerFetch2;
else
-- Fetch VIC-III bitplanes
-- Bitplanes for odd raster lines
if (reg_h640='0' and reg_h1280='0') then
if bitplane_sixteen_colour_mode_flags(sprite_fetch_sprite_number mod 8)='0'
then
-- 320px, mono bitplane = 40 bytes for 320 pixels
max_sprite_fetch_byte_number <= 39;
else
-- 320px, 16-colour bitplane = 160 bytes for 320 pixels
max_sprite_fetch_byte_number <= 159;
end if;
end if;
if (reg_h640='1' and reg_h1280='0') then
if bitplane_sixteen_colour_mode_flags(sprite_fetch_sprite_number mod 8)='0'
then
-- 640px, mono bitplane = 80 bytes for 640 pixels
max_sprite_fetch_byte_number <= 79;
else
-- 640px, 16-colour bitplane = 320 bytes for 640 pixels
max_sprite_fetch_byte_number <= 319;
end if;
end if;
-- Don't waste time fetching bitplanes that are disabled.
if (bitplane_enables(sprite_fetch_sprite_number mod 8)='0')
or (bitplane_mode='0') then
max_sprite_fetch_byte_number <= 1;
end if;
-- Odd bitplanes come from 2nd 64KB RAM, even bitplanes from first.
-- But also allow shifting bitplanes higher in memory
sprite_pointer_address(19 downto 17) <= bitplane_bank_select;
if (sprite_fetch_sprite_number mod 2) = 0 then
sprite_pointer_address(16) <= '0';
else
sprite_pointer_address(16) <= '1';
end if;
-- Interlacing selects which of two bitplane address register
-- fields to use
if (reg_v400='1') and (vicii_ycounter_v400(0)='0') then
-- Use odd scan set
sprite_pointer_address(15 downto 13)
<= bitplane_addresses(sprite_fetch_sprite_number mod 8)
(7 downto 5);
else
-- Use even scan set
sprite_pointer_address(15 downto 13)
<= bitplane_addresses(sprite_fetch_sprite_number mod 8)
(3 downto 1);
end if;
-- XXX: VIC-IV should allow setting of the lower bits of the bitplane
-- address
sprite_pointer_address(12 downto 0) <= (others => '0');
if bitplane_enables(sprite_fetch_sprite_number mod 8)='0' then
-- Don't waste fetch cycles on bitplanes that are turned off
sprite_fetch_byte_number <= 0;
sprite_fetch_sprite_number <= sprite_fetch_sprite_number + 1;
raster_fetch_state <= SpritePointerFetch;
else
--sprite_data_address <= sprite_pointer_address;
--sprite_data_address(12 downto 0) <= to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),13);
raster_fetch_state <= SpritePointerCompute;
--raster_fetch_state <= SpritePointerFetch2;
end if;
end if;
when SpritePointerFetch2 =>
raster_fetch_state <= SpritePointerCompute1;
if vicii_sprite_pointer_address(23)='1' then
-- 16-bit sprite pointers, allowing sprites to be sourced from
-- anywhere in first 64K x 64 = 4MB of chip RAM (of which we
-- currently have only 384KB :)
sprite_pointer_address(19 downto 4) <= vicii_sprite_pointer_address(19 downto 4);
sprite_pointer_address(3 downto 1) <= to_unsigned(sprite_fetch_sprite_number,3);
sprite_pointer_address(0) <= '1';
report "SPRITE: will fetch pointer MSB from $" &
to_hstring(vicii_sprite_pointer_address(19 downto 0) + sprite_fetch_sprite_number*2);
end if;
when SpritePointerCompute1 =>
-- Drive stage for ram data to improve timing closure
raster_fetch_state <= SpritePointerCompute;
when SpritePointerCompute =>
-- Sprite data address is 64*pointer value, plus the 16KB bank
-- from $DD00. Then we need to add the data offset for this sprite.
-- 64-pixel wide and upto 255-pixel heigh extended size sprites means
-- we need to allow the address computation to add the sprite number
-- from the ram data to be added to the upper bits of the
-- sprite_data_offsets() value for the sprite
sprite_data_address(19 downto 16) <= "0000";
if sprite_fetch_sprite_number < 8 then
-- But only accept the new sprite data address at the start of
-- display of a sprite
if sprite_continuous_pointer_monitoring='1' then
sprite_data_address(16) <= '0';
sprite_data_address(15) <= sprite_pointer_address(15);
sprite_data_address(14) <= sprite_pointer_address(14);
sprite_data_address(13 downto 0) <= (ramdata_drive&"000000") + to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),14);
sprite_data_addresses(sprite_fetch_sprite_number)(19 downto 17) <= "000";
sprite_data_addresses(sprite_fetch_sprite_number)(16) <= '0';
sprite_data_addresses(sprite_fetch_sprite_number)(15) <= sprite_pointer_address(15);
sprite_data_addresses(sprite_fetch_sprite_number)(14) <= sprite_pointer_address(14);
sprite_data_addresses(sprite_fetch_sprite_number)(13 downto 0) <= (ramdata_drive&"000000");
else
if sprite_data_offsets(sprite_fetch_sprite_number) /= 0 then
sprite_data_address <= sprite_data_addresses(sprite_fetch_sprite_number) + to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),14);
else
sprite_data_addresses(sprite_fetch_sprite_number)(19 downto 16) <= "0000";
sprite_data_addresses(sprite_fetch_sprite_number)(16) <= '0';
sprite_data_addresses(sprite_fetch_sprite_number)(15) <= sprite_pointer_address(15);
sprite_data_addresses(sprite_fetch_sprite_number)(14) <= sprite_pointer_address(14);
sprite_data_addresses(sprite_fetch_sprite_number)(13 downto 0) <= (ramdata_drive&"000000");
sprite_data_address(19 downto 16) <= "0000";
sprite_data_address(16) <= '0';
sprite_data_address(15) <= sprite_pointer_address(15);
sprite_data_address(14) <= sprite_pointer_address(14);
sprite_data_address(13 downto 0) <= (ramdata_drive&"000000");
end if;
end if;
-- sprite_data_address(5 downto 0) <= to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),6);
report "SPRITE: sprite #"
& integer'image(sprite_fetch_sprite_number)
& " pointer value = $" & to_hstring(ramdata_drive);
else
-- Bitplane fetches happen here
--sprite_data_address <= sprite_pointer_address;
--sprite_data_address(12 downto 0) <= to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),13);
-- sprite_data_address(16) <= '0';
-- sprite_data_address(15) <= sprite_pointer_address(15);
-- sprite_data_address(14) <= sprite_pointer_address(14);
-- sprite_data_address(13 downto 0) <= (ramdata_drive&"000000") + to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),14);
if (reg_h640='1' or reg_h1280='1') then
sprite_data_address(19 downto 14) <= sprite_pointer_address(19 downto 14);
sprite_data_address(13 downto 0) <= to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),14);
else
sprite_data_address(19 downto 13) <= sprite_pointer_address(19 downto 13);
sprite_data_address(12 downto 0) <= to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),13);
end if;
end if;
-- Get MSB if we are using 16-bit sprite pointers
if vicii_sprite_pointer_address(23)='1' then
raster_fetch_state <= SpritePointerComputeMSB;
else
raster_fetch_state <= SpriteDataFetch;
end if;
when SpritePointerComputeMSB =>
-- Copy in MSB bits for sprite data address
-- XXX It would be nice to use bit 7 to indicate to source from
-- colour RAM, but for now we just clip to the 1MB chip RAM range
report "SPRITE: setting upper bits of sprite data address to $" & to_hstring(ramdata_drive);
if sprite_continuous_pointer_monitoring='1' then
sprite_data_address <= (ramdata_drive(5 downto 0)&sprite_data_addresses(sprite_fetch_sprite_number)(13 downto 0))
+ to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),14);
else
if sprite_data_offsets(sprite_fetch_sprite_number) /= 0 then
sprite_data_address <= sprite_data_addresses(sprite_fetch_sprite_number) + to_unsigned(sprite_data_offsets(sprite_fetch_sprite_number),14);
else
sprite_data_address <= sprite_data_addresses(sprite_fetch_sprite_number);
sprite_data_address(19 downto 14) <= ramdata_drive(5 downto 0);
sprite_data_address(13 downto 0) <= sprite_data_address(13 downto 0);
sprite_data_addresses(sprite_fetch_sprite_number)(19 downto 14) <= ramdata_drive(5 downto 0);
sprite_data_addresses(sprite_fetch_sprite_number)(13 downto 0) <= sprite_data_address(13 downto 0);
end if;
end if;
raster_fetch_state <= SpriteDataFetch;
when SpriteDataFetch =>
-- Show what we are doing in debug display mode
render_activity <= "110";
report "SPRITE: fetching sprite #"
& integer'image(sprite_fetch_sprite_number)
& " data from $" & to_hstring(sprite_data_address(19 downto 0));
if sprite_fetch_sprite_number < 8 then
sprite_data_address(19 downto 0) <= sprite_data_address(19 downto 0) + 1;
else
sprite_data_address(19 downto 0) <= sprite_data_address(19 downto 0) + 8;
end if;
raster_fetch_state <= SpriteDataFetch2;
when SpriteDataFetch2 =>
report "SPRITE: fetching sprite #"
& integer'image(sprite_fetch_sprite_number)
& " data = $" &
to_hstring(ramdata)
& " from $" & to_hstring(sprite_data_address(19 downto 0))
& " for byte number " & integer'image(sprite_fetch_byte_number);
if sprite_fetch_sprite_number < 8 then
sprite_data_address(19 downto 0) <= sprite_data_address(19 downto 0) + 1;
else
sprite_data_address(19 downto 0) <= sprite_data_address(19 downto 0) + 8;
end if;
-- Schedule pushing fetched sprite/bitplane byte to next cycle when
-- the data will be available in ramdata_drive
sprite_fetch_drive <= '1';
sprite_fetch_byte_number_drive <= sprite_fetch_byte_number;
sprite_fetch_sprite_number_drive <= sprite_fetch_sprite_number;
sprite_fetch_byte_number <= sprite_fetch_byte_number + 1;
-- XXX - always fetches 8 bytes of sprite data instead of 3, even if
-- sprite is not set to 64 pixels wide mode. This wastes a little
-- raster time.
-- Bitplanes are also fetched using the sprite fetch pipeline, so we fetch
-- more bytes for those, according to the bitplane width.
--if ((sprite_fetch_byte_number = 7) and (sprite_fetch_sprite_number < 8))
if (sprite_fetch_byte_number = max_sprite_fetch_byte_number)
then
sprite_fetch_byte_number <= 0;
sprite_fetch_sprite_number <= sprite_fetch_sprite_number + 1;
raster_fetch_state <= SpritePointerFetch;
end if;
when others => null;
end case;
-- Push sprite data out in a drive cycle to improve timing closure.
if sprite_fetch_drive = '1' then
sprite_datavalid <= '1';
sprite_spritenumber <= sprite_fetch_sprite_number_drive;
sprite_bytenumber <= sprite_fetch_byte_number_drive;
sprite_data_byte <= ramdata_drive;
end if;
raster_buffer_write <= '0';
-- Always write if we are using the primary or alternate palette
raster_buffer_write_data(17) <= paint_alternate_palette xor glyph_alternate_palette_invert;
case paint_fsm_state is
when Idle =>
if paint_ready /= '1' then
paint_ready <= '1';
report "LEGACY: asserting paint_ready" severity note;
end if;
when PaintFullColour =>
-- Draw 8 pixels using a byte at a time from full_colour_data
paint_ready <= '0';
report "LEGACY: clearing paint_ready. full_colour_data=$" & to_hstring(full_colour_data);
paint_full_colour_data <= full_colour_data;
paint_bits_remaining <= paint_glyph_width - 1;
if paint_glyph_4bit='1' then
paint_fsm_state <= Paint4bitColourPixels;
else
paint_fsm_state <= PaintFullColourPixels;
end if;
when Paint4bitColourPixels =>
if paint_full_colour_data(3 downto 0) = x"0" then
-- background pixel
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
raster_buffer_write_data(8) <= force_chars_foreground;
raster_buffer_write_data(7 downto 0) <= paint_background;
else
-- foreground pixel
if paint_with_alpha='0' then
report "LEGACY: full-colour glyph painting pixel $" & to_hstring(paint_full_colour_data(7 downto 0))
& " into buffer @ $" & to_hstring(raster_buffer_write_address);
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
--
raster_buffer_write_data(8) <= not force_chars_background;
if paint_full_colour_data(3 downto 0) /= x"F" then
-- Lower four bits of colour come from the nybl
raster_buffer_write_data(3 downto 0) <= paint_full_colour_data(3 downto 0);
-- Upper four from the foreground colour from screen RAM.
-- This makes it much more useful for paralax layers etc
raster_buffer_write_data(7 downto 4) <= paint_foreground(7 downto 4);
else
raster_buffer_write_data(7 downto 0) <= paint_foreground;
end if;
else
-- XXX Add alternate alpha mode where alhpa value is picked by
-- colour RAM, allowing full colour chars to be faded in and out
-- from background?
report "LEGACY: full-colour glyph painting alpha pixel $"
& to_hstring(paint_foreground)
& " with alpha value $" & to_hstring(paint_full_colour_data(3 downto 0)) & "F"
& " : raster_buffer_write_address=$" & to_hstring(raster_buffer_write_address)
& " ( + 1 ?)";
-- 8-bit pixel values provide the alpha
raster_buffer_write_data(16 downto 13) <= paint_full_colour_data(3 downto 0);
raster_buffer_write_data(12 downto 9) <= (others => paint_full_colour_data(0));
raster_buffer_write_data(8) <= (paint_full_colour_data(3) or force_chars_foreground) and (not force_chars_background);
-- colour RAM colour provides the foreground
raster_buffer_write_data(7 downto 0) <= paint_foreground;
end if;
end if;
paint_full_colour_data(59 downto 0) <= paint_full_colour_data(63 downto 4);
raster_buffer_write_address(9 downto 0) <= raster_buffer_write_address(9 downto 0) + 1;
raster_buffer_max_write_address <= raster_buffer_write_address(9 downto 0) + 1;
if paint_full_colour_data(3 downto 0) /= x"0" or glyph_paint_background='1' then
raster_buffer_write <= '1';
else
raster_buffer_write <= '0';
end if;
report "LEGACY: full colour glyph paint_bits_remaining=" & integer'image(paint_bits_remaining) severity note;
if paint_bits_remaining > 0 then
paint_bits_remaining <= paint_bits_remaining - 1;
else
-- All done
paint_fsm_state <= Idle;
end if;
when PaintFullColourPixels =>
if paint_full_colour_data(7 downto 0) = x"00" then
-- background pixel
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
raster_buffer_write_data(8) <= force_chars_foreground;
raster_buffer_write_data(7 downto 0) <= paint_background;
else
-- foreground pixel
if paint_with_alpha='0' then
report "LEGACY: full-colour glyph painting pixel $" & to_hstring(paint_full_colour_data(7 downto 0))
& " into buffer @ $" & to_hstring(raster_buffer_write_address);
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
raster_buffer_write_data(8) <= not force_chars_background;
if paint_full_colour_data(7 downto 0) /= x"FF" then
raster_buffer_write_data(7 downto 0) <= paint_full_colour_data(7 downto 0);
else
raster_buffer_write_data(7 downto 0) <= paint_foreground;
end if;
else
-- XXX Add alternate alpha mode where alhpa value is picked by
-- colour RAM, allowing full colour chars to be faded in and out
-- from background?
report "LEGACY: full-colour glyph painting alpha pixel $"
& to_hstring(paint_foreground)
& " with alpha value $" & to_hstring(paint_full_colour_data(7 downto 0))
& " : raster_buffer_write_address=$" & to_hstring(raster_buffer_write_address)
& " ( + 1 ?)";
-- 8-bit pixel values provide the alpha
raster_buffer_write_data(16 downto 9) <= paint_full_colour_data(7 downto 0);
raster_buffer_write_data(8) <= (paint_full_colour_data(7) or force_chars_foreground) and (not force_chars_background);
-- colour RAM colour provides the foreground
raster_buffer_write_data(7 downto 0) <= paint_foreground;
end if;
end if;
paint_full_colour_data(55 downto 0) <= paint_full_colour_data(63 downto 8);
raster_buffer_write_address(9 downto 0) <= raster_buffer_write_address(9 downto 0) + 1;
raster_buffer_max_write_address <= raster_buffer_write_address(9 downto 0) + 1;
if glyph_paint_background='1' or paint_full_colour_data(7 downto 0) /= x"00" then
raster_buffer_write <= '1';
else
raster_buffer_write <= '0';
end if;
report "LEGACY: full colour glyph paint_bits_remaining=" & integer'image(paint_bits_remaining) severity note;
if paint_bits_remaining > 0 then
paint_bits_remaining <= paint_bits_remaining - 1;
else
paint_fsm_state <= PaintFullColourDone;
end if;
if paint_bits_remaining = 0 then
-- All done
paint_fsm_state <= Idle;
end if;
when PaintFullColourDone =>
null;
when PaintMono =>
-- Drive stage costs us another cycle per glyph, but seems necessary
-- to meet timing.
report "LEGACY: Painting mono card";
-- Delay of paint_alternate_palette for mono is correct
paint_alternate_palette <= glyph_reverse and glyph_bold;
if glyph_reverse='1' and glyph_bold='0' then
paint_buffer_hflip_chardata <= not paint_chardata;
paint_buffer_noflip_chardata <= not (
paint_chardata(0)&paint_chardata(1)
&paint_chardata(2)&paint_chardata(3)
&paint_chardata(4)&paint_chardata(5)
&paint_chardata(6)&paint_chardata(7));
paint_buffer_hflip_ramdata <= not paint_ramdata;
paint_buffer_noflip_ramdata <= not (
paint_ramdata(0)&paint_ramdata(1)
&paint_ramdata(2)&paint_ramdata(3)
&paint_ramdata(4)&paint_ramdata(5)
&paint_ramdata(6)&paint_ramdata(7));
else
paint_buffer_hflip_chardata <= paint_chardata;
paint_buffer_noflip_chardata <=
paint_chardata(0)&paint_chardata(1)
&paint_chardata(2)&paint_chardata(3)
&paint_chardata(4)&paint_chardata(5)
&paint_chardata(6)&paint_chardata(7);
paint_buffer_hflip_ramdata <= paint_ramdata;
paint_buffer_noflip_ramdata <=
paint_ramdata(0)&paint_ramdata(1)
&paint_ramdata(2)&paint_ramdata(3)
&paint_ramdata(4)&paint_ramdata(5)
&paint_ramdata(6)&paint_ramdata(7);
end if;
if glyph_visible='0' or draw_mask_blank='1' then
paint_buffer_noflip_ramdata <= "00000000";
paint_buffer_hflip_ramdata <= "00000000";
paint_buffer_noflip_chardata <= "00000000";
paint_buffer_hflip_chardata <= "00000000";
end if;
if glyph_underline='1' then
paint_buffer_noflip_ramdata <= "11111111";
paint_buffer_hflip_ramdata <= "11111111";
paint_buffer_noflip_chardata <= "11111111";
paint_buffer_hflip_chardata <= "11111111";
end if;
paint_fsm_state <= PaintMonoDrive;
when PaintMonoDrive =>
-- Paint 8 mono bits from ramdata or chardata
-- Paint from a buffer to meet timing, even though it means we spend
-- 9 cycles per char to paint, instead of the ideal 8.
report "paint_flip_horizontal="&std_logic'image(paint_flip_horizontal)
& ", paint_from_charrom=" & std_logic'image(paint_from_charrom) severity note;
report "LEGACY: painting either $ " & to_hstring(paint_ramdata) & " or $" & to_hstring(paint_chardata) severity note;
report " painting from direct memory would have $ " & to_hstring(ramdata) & " or $" & to_hstring(chardata) severity note;
if paint_flip_horizontal='1' and paint_from_charrom='1' then
paint_buffer <= paint_buffer_hflip_chardata;
elsif paint_flip_horizontal='0' and paint_from_charrom='1' then
paint_buffer <= paint_buffer_noflip_chardata;
elsif paint_flip_horizontal='1' and paint_from_charrom='0' then
paint_buffer <= paint_buffer_hflip_ramdata;
if paint_ramdata(0)='1' then
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
raster_buffer_write_data(8) <= not force_chars_background;
raster_buffer_write_data(7 downto 0) <= paint_foreground;
else
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
raster_buffer_write_data(8) <= not force_chars_foreground;
raster_buffer_write_data(7 downto 0) <= paint_background;
end if;
elsif paint_flip_horizontal='0' and paint_from_charrom='0' then
paint_buffer <= paint_buffer_noflip_ramdata;
end if;
paint_bits_remaining <= paint_glyph_width;
paint_ready <= '0';
raster_buffer_write <= '0';
report "LEGACY: clearing paint_ready";
paint_fsm_state <= PaintMonoBits;
when PaintMonoBits =>
if paint_bits_remaining = paint_glyph_width then
report "painting card using data $" & to_hstring(paint_buffer) severity note;
end if;
if paint_bits_remaining /= 0 then
report "LEGACY: Painting mono char pixel @ $" & to_hstring(raster_buffer_write_address)
& " (" & integer'image(paint_bits_remaining) & " pixels remaining in card.)";
paint_buffer<= '0'&paint_buffer(7 downto 1);
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
if paint_buffer(0)='1' then
raster_buffer_write_data(8) <= not force_chars_background;
raster_buffer_write_data(7 downto 0) <= paint_foreground;
report "Painting foreground pixel in colour $" & to_hstring(paint_foreground) severity note;
else
raster_buffer_write_data(8) <= not force_chars_foreground;
raster_buffer_write_data(7 downto 0) <= paint_background;
report "Painting background pixel in colour $" & to_hstring(paint_background) severity note;
end if;
raster_buffer_write_address(9 downto 0) <= raster_buffer_write_address(9 downto 0) + 1;
raster_buffer_max_write_address <= raster_buffer_write_address(9 downto 0) + 1;
if paint_buffer(0)='1' or glyph_paint_background='1' then
raster_buffer_write <= '1';
else
raster_buffer_write <= '0';
end if;
report "paint_bits_remaining=" & integer'image(paint_bits_remaining) severity note;
paint_bits_remaining <= paint_bits_remaining - 1;
end if;
if paint_bits_remaining = 1 or paint_bits_remaining = 0 then
paint_fsm_state <= Idle;
end if;
when PaintMultiColour =>
-- Drive stage costs us another cycle per glyph, but seems necessary
-- to meet timing.
-- Paint_alternate_palette seems to not work in multi-colour mode
paint_alternate_palette <= glyph_reverse and glyph_bold;
if glyph_reverse='1' and glyph_bold='0' then
paint_buffer_hflip_chardata <= not paint_chardata;
paint_buffer_noflip_chardata <= not (
paint_chardata(0)&paint_chardata(1)
&paint_chardata(2)&paint_chardata(3)
&paint_chardata(4)&paint_chardata(5)
&paint_chardata(6)&paint_chardata(7));
paint_buffer_hflip_ramdata <= not paint_ramdata;
paint_buffer_noflip_ramdata <= not (
paint_ramdata(0)&paint_ramdata(1)
&paint_ramdata(2)&paint_ramdata(3)
&paint_ramdata(4)&paint_ramdata(5)
&paint_ramdata(6)&paint_ramdata(7));
else
paint_buffer_hflip_chardata <= paint_chardata;
paint_buffer_noflip_chardata <=
paint_chardata(0)&paint_chardata(1)
&paint_chardata(2)&paint_chardata(3)
&paint_chardata(4)&paint_chardata(5)
&paint_chardata(6)&paint_chardata(7);
paint_buffer_hflip_ramdata <= paint_ramdata;
paint_buffer_noflip_ramdata <=
paint_ramdata(0)&paint_ramdata(1)
&paint_ramdata(2)&paint_ramdata(3)
&paint_ramdata(4)&paint_ramdata(5)
&paint_ramdata(6)&paint_ramdata(7);
end if;
if glyph_visible='0' or draw_mask_blank='1' then
paint_buffer_noflip_ramdata <= "00000000";
paint_buffer_hflip_ramdata <= "00000000";
paint_buffer_noflip_chardata <= "00000000";
paint_buffer_hflip_chardata <= "00000000";
end if;
if glyph_underline='1' then
paint_buffer_noflip_ramdata <= "11111111";
paint_buffer_hflip_ramdata <= "11111111";
paint_buffer_noflip_chardata <= "11111111";
paint_buffer_hflip_chardata <= "11111111";
end if;
paint_fsm_state <= PaintMultiColourDrive;
when PaintMultiColourDrive =>
-- Paint 4 multi-colour half-nybls from ramdata or chardata
-- Paint from a buffer to meet timing, even though it means we spend
-- 5 cycles per char to paint, instead of the ideal 4.
report "paint_flip_horizontal="&std_logic'image(paint_flip_horizontal)
& ", paint_from_charrom=" & std_logic'image(paint_from_charrom) severity note;
if raster_buffer_write_address(9 downto 0) = 0 then
report "painting either $ " & to_hstring(paint_ramdata) & " or $" & to_hstring(paint_chardata) severity note;
report " painting from direct memory would have $ " & to_hstring(ramdata) & " or $" & to_hstring(chardata) severity note;
end if;
if paint_flip_horizontal='1' and paint_from_charrom='1' then
paint_buffer <= paint_buffer_hflip_chardata;
elsif paint_flip_horizontal='0' and paint_from_charrom='1' then
paint_buffer <= paint_buffer_noflip_chardata;
elsif paint_flip_horizontal='1' and paint_from_charrom='0' then
paint_buffer <= paint_buffer_hflip_ramdata;
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
if paint_ramdata(0)='1' then
raster_buffer_write_data(8) <= not force_chars_background;
raster_buffer_write_data(7 downto 0) <= paint_foreground;
else
raster_buffer_write_data(8) <= not force_chars_foreground;
raster_buffer_write_data(7 downto 0) <= paint_background;
end if;
elsif paint_flip_horizontal='0' and paint_from_charrom='0' then
paint_buffer <= paint_buffer_noflip_ramdata;
end if;
paint_bits_remaining <= (paint_glyph_width / 2);
paint_ready <= '0';
report "LEGACY: clearing paint_ready";
paint_fsm_state <= PaintMultiColourBits;
when PaintMultiColourBits =>
if paint_bits_remaining = (paint_glyph_width / 2) then
report "painting card using data $" & to_hstring(paint_buffer) severity note;
end if;
if paint_bits_remaining /= 0 then
paint_buffer<= "00"&paint_buffer(7 downto 2);
raster_buffer_write_data(16 downto 9) <= x"FF"; -- solid alpha
case paint_buffer(1 downto 0) is
when "00" =>
raster_buffer_write_data(8) <= not force_chars_foreground;
raster_buffer_write_data(7 downto 0) <= paint_background;
report "Painting background pixel in colour $" & to_hstring(paint_background) severity note;
when "01" =>
raster_buffer_write_data(8) <= not force_chars_background;
raster_buffer_write_data(7 downto 0) <= paint_mc1;
report "Painting multi-colour 2 pixel in colour $" & to_hstring(paint_mc1) severity note;
when "10" =>
raster_buffer_write_data(8) <= not force_chars_background;
raster_buffer_write_data(7 downto 0) <= paint_mc2;
report "Painting multi-colour 3 pixel in colour $" & to_hstring(paint_mc2) severity note;
when "11" =>
raster_buffer_write_data(8) <= not force_chars_background;
raster_buffer_write_data(7 downto 0) <= paint_foreground;
report "Painting foreground pixel in colour $" & to_hstring(paint_foreground) severity note;
when others =>
null;
end case;
raster_buffer_write_address(9 downto 0) <= raster_buffer_write_address(9 downto 0) + 1;
raster_buffer_max_write_address <= raster_buffer_write_address(9 downto 0) + 1;
if paint_buffer(1 downto 0) /= "00" or glyph_paint_background='1' then
raster_buffer_write <= '1';
else
raster_buffer_write <= '0';
end if;
report "paint_bits_remaining=" & integer'image(paint_bits_remaining) severity note;
paint_bits_remaining <= paint_bits_remaining - 1;
end if;
-- Stretch multi-colour pixels to be double width
paint_fsm_state <= PaintMultiColourHold;
when PaintMultiColourHold =>
raster_buffer_write_address(9 downto 0) <= raster_buffer_write_address(9 downto 0) + 1;
raster_buffer_max_write_address <= raster_buffer_write_address(9 downto 0) + 1;
if paint_buffer(1 downto 0) /= "00" or glyph_paint_background='1' then
raster_buffer_write <= '1';
else
raster_buffer_write <= '0';
end if;
if paint_bits_remaining = 0 then
paint_fsm_state <= Idle;
else
paint_fsm_state <= PaintMultiColourBits;
end if;
when others =>
-- If we don't know what to do, just smile and nod and say we are
-- ready again.
paint_fsm_state <= Idle;
end case;
if raster_fetch_state /= Idle or paint_fsm_state /= Idle then
report "raster_fetch_state=" & vic_chargen_fsm'image(raster_fetch_state) & ", "
& "paint_fsm_state=" & vic_paint_fsm'image(paint_fsm_state)
& ", rb_w_addr=$" & to_hstring(raster_buffer_write_address) severity note;
end if;
end if;
end process;
-- charaddress generation
process(raster_fetch_state,glyph_data_address,reg_char_y16,charrow_repeated)
begin
if reg_char_y16 = '0' then
charaddress <= safe_to_integer(glyph_data_address(11 downto 0));
else
if charrow_repeated='0' then
charaddress <= safe_to_integer(glyph_data_address(10 downto 0));
else
charaddress <= 2048 + safe_to_integer(glyph_data_address(10 downto 0));
end if;
end if;
--charaddress <= to_unsigned(0,12);
--case raster_fetch_state is
-- when FetchBitmapData =>
-- report "setting charaddress to " & integer'image(safe_to_integer(glyph_data_address(10 downto 0)))
-- & " for painting glyph $" & to_hstring(to_unsigned(safe_to_integer(glyph_number),16)) severity note;
-- charaddress <= safe_to_integer(glyph_data_address(11 downto 0));
-- when FetchTextCellColourAndSource =>
-- -- upper bit of charrom address is set by $D018, only 258*8 = 2K
-- -- range of address is controlled here by character number.
-- report "setting charaddress to " & integer'image(safe_to_integer(glyph_data_address(10 downto 0)))
-- & " for painting glyph $" & to_hstring(to_unsigned(safe_to_integer(glyph_number),16)) severity note;
-- charaddress <= safe_to_integer(glyph_data_address(11 downto 0));
-- when others => null;
-- end case;
end process;
-- raster buffer read address/sub calculations
-- pulled out so "next" value can be fed directly to raster buffer ram read address.
process(raster_buffer_read_address,raster_buffer_read_address_sub,chargen_x_scale_drive,xcounter,x_chargen_start_minus1,
reg_h640)
begin
raster_buffer_read_address_next <= raster_buffer_read_address;
if xcounter = x_chargen_start_minus1 then
-- Request first byte of pre-rendered character data
report "raster fetch raster_buffer_read_address reset to zero at start of chargen";
raster_buffer_read_address_next(9 downto 0) <= (others => '0');
raster_buffer_read_address_sub_next(9 downto 0) <= (others => '0');
else
if reg_h640='1' then
-- 640 wide characters use x scale directly
if raster_buffer_read_address_sub >= 240 then
raster_buffer_read_address_sub_next <= raster_buffer_read_address_sub - 240 + chargen_x_scale_drive;
raster_buffer_read_address_next(9 downto 0) <= raster_buffer_read_address(9 downto 0) + 2;
elsif raster_buffer_read_address_sub >= 120 then
raster_buffer_read_address_sub_next <= raster_buffer_read_address_sub - 120 + chargen_x_scale_drive;
raster_buffer_read_address_next(9 downto 0) <= raster_buffer_read_address(9 downto 0) + 1;
else
raster_buffer_read_address_sub_next <= raster_buffer_read_address_sub + chargen_x_scale_drive;
end if;
else
-- 320 wide / 40 column text is 2x as wide, i.e., we halve the x scale
-- factor.
if raster_buffer_read_address_sub >= 240 then
raster_buffer_read_address_sub_next <= raster_buffer_read_address_sub - 240 + chargen_x_scale_drive(7 downto 1);
raster_buffer_read_address_next(9 downto 0) <= raster_buffer_read_address(9 downto 0) + 2;
elsif raster_buffer_read_address_sub >= 120 then
raster_buffer_read_address_sub_next <= raster_buffer_read_address_sub - 120 + chargen_x_scale_drive(7 downto 1);
raster_buffer_read_address_next(9 downto 0) <= raster_buffer_read_address(9 downto 0) + 1;
else
raster_buffer_read_address_sub_next <= raster_buffer_read_address_sub + chargen_x_scale_drive(7 downto 1);
end if;
end if;
end if;
end process;
-- ramaddress mux
-- This is pulled out into a combinatorial section so that ramaddress changes as soon as the raster_fetch_state
-- value changes so that it can be driven into the block ram and sampled at the next clock cycle, thus providing the
-- expected data on the next clock as well.
process(raster_fetch_state,this_ramaccess_is_screen_row_fetch,glyph_data_address,sprite_pointer_address,sprite_data_address,
ramaddress,this_screen_row_fetch_address,glyph_full_colour)
begin
next_ramaddress <= ramaddress;
if this_ramaccess_is_screen_row_fetch='1' then
report "chipram fetch for screen row data from $" & to_hstring(to_unsigned(safe_to_integer(this_screen_row_fetch_address),16));
next_ramaddress <= this_screen_row_fetch_address;
end if;
case raster_fetch_state is
when FetchBitmapData =>
-- Ask for first byte of data so that paint can commence immediately.
report "setting ramaddress to $" & to_hstring("000"&glyph_data_address) & " for glyph painting." severity note;
next_ramaddress <= glyph_data_address;
when FetchTextCellColourAndSource =>
-- Ask for first byte of data so that paint can commence immediately.
report "setting ramaddress to $" & to_hstring("000"&glyph_data_address) & " for glyph painting." severity note;
next_ramaddress <= glyph_data_address;
when PaintMemWait =>
if glyph_full_colour = '1' then
report "setting ramaddress to $" & to_hstring(glyph_data_address) & " for full-colour glyph drawing";
next_ramaddress <= glyph_data_address;
end if;
when PaintMemWait2 =>
if glyph_full_colour = '1' then
report "LEGACY: setting ramaddress to $" & to_hstring(glyph_data_address) & " for full-colour glyph drawing";
next_ramaddress <= glyph_data_address;
end if;
when PaintFullColourFetch =>
report "setting ramaddress to $" & to_hstring(glyph_data_address) & " for full-colour glyph drawing";
next_ramaddress <= glyph_data_address;
when SpritePointerFetch2 =>
next_ramaddress <= sprite_pointer_address;
when SpritePointerCompute1 =>
next_ramaddress <= sprite_pointer_address;
when SpriteDataFetch =>
next_ramaddress <= sprite_data_address;
when SpriteDataFetch2 =>
next_ramaddress <= sprite_data_address;
when others => null;
end case;
end process;
process (pixelclock) is
begin
if rising_edge(pixelclock) then
-- XXX Export $D031 mystery writes debug signal
d031_written <= d031_written_internal;
--Route out position counters for compositor
--But delay them for the video pipeline depth.
--1 pixel stage + 8 sprite + 8 bitplane = 17 cycles
xcounter_out <= xcounter_pipeline_delayed;
report "VICIV: xcounter=" & integer'image(to_integer(xcounter))
& ", ycounter=" & integer'image(to_integer(ycounter));
sprite_h640_delayed <= sprite_h640;
sprite_v400s_delayed <= sprite_v400s;
reg_h640_delayed <= reg_h640;
reg_h1280_delayed <= reg_h1280;
external_frame_x_zero_latched <= external_frame_x_zero;
last_external_frame_x_zero_latched <= external_frame_x_zero_latched;
-- ycounter we can watch for changes and count down, instead of having to have
-- 17 copies of it
-- if ycounter /= ycounter_last then
-- ycounter_export_countdown <= 17;
-- else
-- if ycounter_export_countdown /= 0 then
-- ycounter_export_countdown <= ycounter_export_countdown - 1;
-- ycounter_out <= safe_to_integer(ycounter_last);
-- ycounter_out <= safe_to_integer(ycounter);
-- else
-- end if;
-- end if;
end if;
end process;
ycounter_out <= safe_to_integer(ycounter);
end Behavioral;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment