mirror of
https://github.com/MiSTer-devel/Genesis_MiSTer.git
synced 2026-05-17 03:03:45 +00:00
- SP3 now starts at correct position, apply DE to sprite buffer - Overflow flag should be set in SP3 only Fixes #38 flickering graphics in Alex Kidd in the Enchanted Castle
3618 lines
106 KiB
VHDL
3618 lines
106 KiB
VHDL
-- Copyright (c) 2010 Gregory Estrade (greg@torlus.com)
|
|
-- Copyright (c) 2018 Till Harbaum
|
|
-- Copyright (c) 2018-2019 Alexey Melnikov
|
|
-- Copyright (c) 2018-2019 György Szombathelyi
|
|
--
|
|
-- All rights reserved
|
|
--
|
|
-- Redistribution and use in source and synthezised forms, with or without
|
|
-- modification, are permitted provided that the following conditions are met:
|
|
--
|
|
-- Redistributions of source code must retain the above copyright notice,
|
|
-- this list of conditions and the following disclaimer.
|
|
--
|
|
-- Redistributions in synthesized form must reproduce the above copyright
|
|
-- notice, this list of conditions and the following disclaimer in the
|
|
-- documentation and/or other materials provided with the distribution.
|
|
--
|
|
-- Neither the name of the author nor the names of other contributors may
|
|
-- be used to endorse or promote products derived from this software without
|
|
-- specific prior written permission.
|
|
--
|
|
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
|
|
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
-- POSSIBILITY OF SUCH DAMAGE.
|
|
--
|
|
-- Please report bugs to the author, but before you do so, please
|
|
-- make sure that this is not a derivative work and that
|
|
-- you have the latest version of this file.
|
|
|
|
-- TODOs/Known issues (according to http://md.squee.co/VDP)
|
|
-- - window has priority over sprites?
|
|
|
|
library IEEE;
|
|
use IEEE.STD_LOGIC_1164.ALL;
|
|
use IEEE.STD_LOGIC_ARITH.ALL;
|
|
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
|
use IEEE.STD_LOGIC_TEXTIO.all;
|
|
library STD;
|
|
use STD.TEXTIO.ALL;
|
|
use work.vdp_common.all;
|
|
|
|
entity vdp is
|
|
port(
|
|
RST_N : in std_logic;
|
|
CLK : in std_logic;
|
|
|
|
SEL : in std_logic;
|
|
A : in std_logic_vector(4 downto 0);
|
|
RNW : in std_logic;
|
|
DI : in std_logic_vector(15 downto 0);
|
|
DO : out std_logic_vector(15 downto 0);
|
|
DTACK_N : out std_logic;
|
|
|
|
vram_req : out std_logic;
|
|
vram_ack : in std_logic;
|
|
vram_we : out std_logic;
|
|
vram_a : out std_logic_vector(15 downto 1);
|
|
vram_d : out std_logic_vector(15 downto 0);
|
|
vram_q : in std_logic_vector(15 downto 0);
|
|
vram_u_n : out std_logic;
|
|
vram_l_n : out std_logic;
|
|
|
|
vram32_req : out std_logic;
|
|
vram32_ack : in std_logic;
|
|
vram32_a : out std_logic_vector(15 downto 1);
|
|
vram32_q : in std_logic_vector(31 downto 0);
|
|
|
|
HINT : out std_logic;
|
|
VINT_TG68 : out std_logic;
|
|
VINT_T80 : out std_logic;
|
|
INTACK : in std_logic;
|
|
BR_N : out std_logic;
|
|
BG_N : in std_logic;
|
|
BGACK_N : out std_logic;
|
|
|
|
VBUS_ADDR : out std_logic_vector(23 downto 1);
|
|
VBUS_DATA : in std_logic_vector(15 downto 0);
|
|
|
|
VBUS_SEL : out std_logic;
|
|
VBUS_DTACK_N: in std_logic;
|
|
|
|
PAL : in std_logic := '0';
|
|
|
|
CE_PIX : buffer std_logic;
|
|
FIELD_OUT : out std_logic;
|
|
INTERLACE : out std_logic;
|
|
RESOLUTION : out std_logic_vector(1 downto 0);
|
|
HBL : out std_logic;
|
|
VBL : out std_logic;
|
|
|
|
R : out std_logic_vector(3 downto 0);
|
|
G : out std_logic_vector(3 downto 0);
|
|
B : out std_logic_vector(3 downto 0);
|
|
HS : out std_logic;
|
|
VS : out std_logic;
|
|
|
|
SVP_QUIRK : in std_logic := '0';
|
|
VRAM_SPEED : in std_logic := '1'; -- 0 - full speed, 1 - FIFO throttle emulation
|
|
VSCROLL_BUG : in std_logic := '1'; -- 0 - use nicer effect, 1 - HW original
|
|
BORDER_EN : in std_logic := '1'; -- Enable border
|
|
OBJ_LIMIT_HIGH_EN : in std_logic := '0' -- Enable more sprites and pixels per line
|
|
);
|
|
end vdp;
|
|
|
|
architecture rtl of vdp is
|
|
|
|
signal vram_a_reg : std_logic_vector(16 downto 1);
|
|
signal vram32_a_reg : std_logic_vector(15 downto 1);
|
|
signal vram32_a_next: std_logic_vector(15 downto 1);
|
|
|
|
signal vram32_req_reg : std_logic;
|
|
----------------------------------------------------------------
|
|
-- ON-CHIP RAMS
|
|
----------------------------------------------------------------
|
|
signal CRAM_ADDR_A : std_logic_vector(5 downto 0);
|
|
signal CRAM_ADDR_B : std_logic_vector(5 downto 0);
|
|
signal CRAM_D_A : std_logic_vector(8 downto 0);
|
|
signal CRAM_WE_A : std_logic;
|
|
signal CRAM_WE_B : std_logic;
|
|
signal CRAM_Q_A : std_logic_vector(8 downto 0);
|
|
signal CRAM_Q_B : std_logic_vector(8 downto 0);
|
|
|
|
signal VSRAM0_ADDR_A : std_logic_vector( 4 downto 0);
|
|
signal VSRAM0_ADDR_B : std_logic_vector( 4 downto 0);
|
|
signal VSRAM0_D_A : std_logic_vector(10 downto 0);
|
|
signal VSRAM0_WE_A : std_logic;
|
|
signal VSRAM0_WE_B : std_logic;
|
|
signal VSRAM0_Q_A : std_logic_vector(10 downto 0);
|
|
signal VSRAM0_Q_B : std_logic_vector(10 downto 0);
|
|
|
|
signal VSRAM1_ADDR_A : std_logic_vector( 4 downto 0);
|
|
signal VSRAM1_ADDR_B : std_logic_vector( 4 downto 0);
|
|
signal VSRAM1_D_A : std_logic_vector(10 downto 0);
|
|
signal VSRAM1_WE_A : std_logic;
|
|
signal VSRAM1_WE_B : std_logic;
|
|
signal VSRAM1_Q_A : std_logic_vector(10 downto 0);
|
|
signal VSRAM1_Q_B : std_logic_vector(10 downto 0);
|
|
|
|
----------------------------------------------------------------
|
|
-- CPU INTERFACE
|
|
----------------------------------------------------------------
|
|
signal FF_DTACK_N : std_logic;
|
|
signal FF_DO : std_logic_vector(15 downto 0);
|
|
|
|
type reg_t is array(0 to 31) of std_logic_vector(7 downto 0);
|
|
signal REG : reg_t;
|
|
signal PENDING : std_logic;
|
|
signal CODE : std_logic_vector(5 downto 0);
|
|
|
|
type fifo_addr_t is array(0 to 3) of std_logic_vector(16 downto 0);
|
|
signal FIFO_ADDR : fifo_addr_t;
|
|
type fifo_data_t is array(0 to 3) of std_logic_vector(15 downto 0);
|
|
signal FIFO_DATA : fifo_data_t;
|
|
type fifo_code_t is array(0 to 3) of std_logic_vector(3 downto 0);
|
|
signal FIFO_CODE : fifo_code_t;
|
|
type fifo_delay_t is array(0 to 3) of std_logic_vector(1 downto 0);
|
|
signal FIFO_DELAY : fifo_delay_t;
|
|
signal FIFO_WR_POS : std_logic_vector(1 downto 0);
|
|
signal FIFO_RD_POS : std_logic_vector(1 downto 0);
|
|
signal FIFO_QUEUE : std_logic_vector(2 downto 0);
|
|
signal FIFO_EMPTY : std_logic;
|
|
signal FIFO_FULL : std_logic;
|
|
signal REFRESH_SLOT : std_logic;
|
|
signal REFRESH_FLAG : std_logic;
|
|
signal REFRESH_EN : std_logic;
|
|
signal FIFO_EN : std_logic;
|
|
signal FIFO_PARTIAL : std_logic;
|
|
signal SLOT_EN : std_logic;
|
|
|
|
signal IN_DMA : std_logic;
|
|
signal IN_HBL : std_logic;
|
|
signal M_HBL : std_logic;
|
|
signal IN_VBL : std_logic; -- VBL flag to the CPU
|
|
signal VBL_AREA : std_logic; -- outside of borders
|
|
|
|
signal SOVR : std_logic;
|
|
signal SOVR_SET : std_logic;
|
|
signal SOVR_CLR : std_logic;
|
|
|
|
signal SCOL : std_logic;
|
|
signal SCOL_SET : std_logic;
|
|
signal SCOL_CLR : std_logic;
|
|
|
|
----------------------------------------------------------------
|
|
-- INTERRUPTS
|
|
----------------------------------------------------------------
|
|
signal HINT_COUNT : std_logic_vector(7 downto 0);
|
|
signal HINT_EN : std_logic;
|
|
signal HINT_PENDING : std_logic;
|
|
signal HINT_PENDING_SET : std_logic;
|
|
signal HINT_FF : std_logic;
|
|
|
|
signal VINT_TG68_PENDING : std_logic;
|
|
signal VINT_TG68_PENDING_SET : std_logic;
|
|
signal VINT_TG68_FF : std_logic;
|
|
|
|
signal VINT_T80_SET : std_logic;
|
|
signal VINT_T80_CLR : std_logic;
|
|
signal VINT_T80_FF : std_logic;
|
|
|
|
signal INTACK_D : std_logic;
|
|
----------------------------------------------------------------
|
|
-- REGISTERS
|
|
----------------------------------------------------------------
|
|
signal RS0 : std_logic;
|
|
signal H40 : std_logic;
|
|
signal V30 : std_logic;
|
|
signal SHI : std_logic;
|
|
|
|
signal ADDR_STEP : std_logic_vector(7 downto 0);
|
|
|
|
signal HSCR : std_logic_vector(1 downto 0);
|
|
signal HSIZE : std_logic_vector(1 downto 0);
|
|
signal VSIZE : std_logic_vector(1 downto 0);
|
|
signal VSCR : std_logic;
|
|
|
|
signal WVP : std_logic_vector(4 downto 0);
|
|
signal WDOWN : std_logic;
|
|
signal WHP : std_logic_vector(4 downto 0);
|
|
signal WHP_LATCH : std_logic_vector(4 downto 0);
|
|
signal WRIGT : std_logic;
|
|
signal WRIGT_LATCH : std_logic;
|
|
|
|
signal BGCOL : std_logic_vector(5 downto 0);
|
|
|
|
signal HIT : std_logic_vector(7 downto 0);
|
|
signal IE1 : std_logic;
|
|
signal IE0 : std_logic;
|
|
|
|
signal M3 : std_logic;
|
|
signal DE : std_logic;
|
|
signal M5 : std_logic;
|
|
|
|
signal M128 : std_logic;
|
|
signal DMA : std_logic;
|
|
|
|
signal LSM : std_logic_vector(1 downto 0);
|
|
signal ODD : std_logic;
|
|
|
|
signal HV : std_logic_vector(15 downto 0);
|
|
signal STATUS : std_logic_vector(15 downto 0);
|
|
signal DBG : std_logic_vector(15 downto 0);
|
|
|
|
-- Base addresses
|
|
signal HSCB : std_logic_vector(5 downto 0);
|
|
signal NTBB : std_logic_vector(2 downto 0);
|
|
signal NTWB : std_logic_vector(4 downto 0);
|
|
signal NTAB : std_logic_vector(2 downto 0);
|
|
signal SATB : std_logic_vector(7 downto 0);
|
|
|
|
|
|
|
|
----------------------------------------------------------------
|
|
-- DATA TRANSFER CONTROLLER
|
|
----------------------------------------------------------------
|
|
type dtc_t is (
|
|
DTC_IDLE,
|
|
DTC_FIFO_RD,
|
|
DTC_VRAM_WR1,
|
|
DTC_VRAM_WR2,
|
|
DTC_CRAM_WR,
|
|
DTC_VSRAM_WR,
|
|
DTC_WR_END,
|
|
DTC_VRAM_RD1,
|
|
DTC_VRAM_RD2,
|
|
DTC_CRAM_RD,
|
|
DTC_CRAM_RD1,
|
|
DTC_CRAM_RD2,
|
|
DTC_VSRAM_RD,
|
|
DTC_VSRAM_RD2,
|
|
DTC_VSRAM_RD3
|
|
);
|
|
signal DTC : dtc_t;
|
|
|
|
type dmac_t is (
|
|
DMA_IDLE,
|
|
DMA_FILL_INIT,
|
|
DMA_FILL_START,
|
|
DMA_FILL_CRAM,
|
|
DMA_FILL_VSRAM,
|
|
DMA_FILL_WR,
|
|
DMA_FILL_WR2,
|
|
DMA_FILL_NEXT,
|
|
DMA_FILL_LOOP,
|
|
DMA_COPY_INIT,
|
|
DMA_COPY_RD,
|
|
DMA_COPY_RD2,
|
|
DMA_COPY_WR,
|
|
DMA_COPY_WR2,
|
|
DMA_COPY_LOOP,
|
|
DMA_VBUS_INIT,
|
|
DMA_VBUS_WAIT,
|
|
DMA_VBUS_RD,
|
|
DMA_VBUS_LOOP,
|
|
DMA_VBUS_END
|
|
);
|
|
signal DMAC : dmac_t;
|
|
|
|
signal DT_VRAM_SEL : std_logic;
|
|
signal DT_VRAM_SEL_D : std_logic;
|
|
signal DT_VRAM_ADDR : std_logic_vector(16 downto 1);
|
|
signal DT_VRAM_DI : std_logic_vector(15 downto 0);
|
|
signal DT_VRAM_DO : std_logic_vector(15 downto 0);
|
|
signal DT_VRAM_RNW : std_logic;
|
|
signal DT_VRAM_UDS_N : std_logic;
|
|
signal DT_VRAM_LDS_N : std_logic;
|
|
|
|
signal DT_WR_ADDR : std_logic_vector(16 downto 0);
|
|
signal DT_WR_DATA : std_logic_vector(15 downto 0);
|
|
|
|
signal DT_RD_DATA : std_logic_vector(15 downto 0);
|
|
signal DT_RD_CODE : std_logic_vector(3 downto 0);
|
|
signal DT_RD_SEL : std_logic;
|
|
signal DT_RD_DTACK_N : std_logic;
|
|
|
|
signal ADDR : std_logic_vector(16 downto 0);
|
|
|
|
signal DT_DMAF_DATA : std_logic_vector(15 downto 0);
|
|
signal DT_DMAV_DATA : std_logic_vector(15 downto 0);
|
|
signal DMAF_SET_REQ : std_logic;
|
|
|
|
signal FF_VBUS_ADDR : std_logic_vector(23 downto 1);
|
|
signal FF_VBUS_SEL : std_logic;
|
|
|
|
signal DMA_VBUS : std_logic;
|
|
signal DMA_FILL : std_logic;
|
|
signal DMA_COPY : std_logic;
|
|
|
|
signal DMA_LENGTH : std_logic_vector(15 downto 0);
|
|
signal DMA_SOURCE : std_logic_vector(15 downto 0);
|
|
|
|
signal DMA_VBUS_TIMER : std_logic_vector(1 downto 0);
|
|
signal BGACK_N_REG : std_logic;
|
|
|
|
----------------------------------------------------------------
|
|
-- VIDEO COUNTING
|
|
----------------------------------------------------------------
|
|
signal V_ACTIVE : std_logic; -- V_ACTIVE right after line change
|
|
signal V_ACTIVE_DISP : std_logic; -- V_ACTIVE after HBLANK_START
|
|
signal Y : std_logic_vector(7 downto 0);
|
|
signal BG_Y : std_logic_vector(8 downto 0);
|
|
|
|
signal PRE_V_ACTIVE : std_logic;
|
|
signal PRE_Y : std_logic_vector(8 downto 0);
|
|
|
|
signal FIELD : std_logic;
|
|
signal FIELD_LATCH : std_logic;
|
|
|
|
-- HV COUNTERS
|
|
signal HV_PIXDIV : std_logic_vector(3 downto 0);
|
|
signal HV_HCNT : std_logic_vector(8 downto 0);
|
|
signal HV_VCNT : std_logic_vector(8 downto 0);
|
|
signal HV_VCNT_EXT : std_logic_vector(8 downto 0);
|
|
signal HV8 : std_logic;
|
|
|
|
-- TIMING VALUES
|
|
signal H_DISP_START : std_logic_vector(8 downto 0);
|
|
signal H_DISP_WIDTH : std_logic_vector(8 downto 0);
|
|
signal H_TOTAL_WIDTH : std_logic_vector(8 downto 0);
|
|
signal H_SPENGINE_ON : std_logic_vector(8 downto 0);
|
|
signal H_INT_POS : std_logic_vector(8 downto 0);
|
|
signal HSYNC_START : std_logic_vector(8 downto 0);
|
|
signal HSYNC_END : std_logic_vector(8 downto 0);
|
|
signal HBLANK_START : std_logic_vector(8 downto 0);
|
|
signal HBLANK_END : std_logic_vector(8 downto 0);
|
|
signal HSCROLL_READ : std_logic_vector(8 downto 0);
|
|
signal V_DISP_START : std_logic_vector(8 downto 0);
|
|
signal V_DISP_HEIGHT : std_logic_vector(8 downto 0);
|
|
signal VSYNC_HSTART : std_logic_vector(8 downto 0);
|
|
signal VSYNC_START : std_logic_vector(8 downto 0);
|
|
signal VBORDER_START : std_logic_vector(8 downto 0);
|
|
signal VBORDER_END : std_logic_vector(8 downto 0);
|
|
signal V_TOTAL_HEIGHT : std_logic_vector(8 downto 0);
|
|
signal V_INT_POS : std_logic_vector(8 downto 0);
|
|
|
|
signal V_DISP_HEIGHT_R : std_logic_vector(8 downto 0);
|
|
signal V30_R : std_logic;
|
|
|
|
----------------------------------------------------------------
|
|
-- VRAM CONTROLLER
|
|
----------------------------------------------------------------
|
|
|
|
signal early_ack_dt : std_logic;
|
|
|
|
type vmc32_t is (
|
|
VMC32_IDLE,
|
|
VMC32_HSC,
|
|
VMC32_BGB,
|
|
VMC32_BGA,
|
|
VMC32_SP2,
|
|
VMC32_SP3
|
|
);
|
|
signal VMC32 : vmc32_t := VMC32_IDLE;
|
|
signal VMC32_NEXT : vmc32_t := VMC32_IDLE;
|
|
signal RAM_REQ_PROGRESS : std_logic;
|
|
|
|
----------------------------------------------------------------
|
|
-- HSCROLL READING
|
|
----------------------------------------------------------------
|
|
|
|
signal HSC_VRAM_ADDR : std_logic_vector(15 downto 1);
|
|
signal HSC_VRAM32_DO : std_logic_vector(31 downto 0);
|
|
signal HSC_VRAM32_DO_REG: std_logic_vector(31 downto 0);
|
|
signal HSC_VRAM32_ACK : std_logic;
|
|
signal HSC_SEL : std_logic;
|
|
|
|
----------------------------------------------------------------
|
|
-- BACKGROUND RENDERING
|
|
----------------------------------------------------------------
|
|
|
|
signal BGEN_ACTIVATE : std_logic;
|
|
|
|
-- BACKGROUND B
|
|
type bgbc_t is (
|
|
BGBC_INIT,
|
|
BGBC_GET_VSCROLL,
|
|
BGBC_GET_VSCROLL2,
|
|
BGBC_GET_VSCROLL3,
|
|
BGBC_CALC_Y,
|
|
BGBC_CALC_BASE,
|
|
BGBC_BASE_RD,
|
|
BGBC_TILE_RD,
|
|
BGBC_LOOP,
|
|
BGBC_DONE
|
|
);
|
|
signal BGBC : bgbc_t;
|
|
|
|
-- signal BGB_COLINFO : colinfo_t;
|
|
signal BGB_COLINFO_ADDR_A : std_logic_vector(8 downto 0);
|
|
signal BGB_COLINFO_ADDR_B : std_logic_vector(8 downto 0);
|
|
signal BGB_COLINFO_D_A : std_logic_vector(6 downto 0);
|
|
signal BGB_COLINFO_WE_A : std_logic;
|
|
signal BGB_COLINFO_WE_B : std_logic;
|
|
signal BGB_COLINFO_Q_B : std_logic_vector(6 downto 0);
|
|
|
|
|
|
signal BGB_X : std_logic_vector(9 downto 0);
|
|
signal BGB_POS : std_logic_vector(9 downto 0);
|
|
signal BGB_COL : std_logic_vector(6 downto 0);
|
|
signal BGB_Y : std_logic_vector(10 downto 0);
|
|
signal T_BGB_PRI : std_logic;
|
|
signal T_BGB_PAL : std_logic_vector(1 downto 0);
|
|
signal T_BGB_COLNO : std_logic_vector(3 downto 0);
|
|
signal BGB_BASE : std_logic_vector(15 downto 0);
|
|
signal BGB_HF : std_logic;
|
|
|
|
signal BGB_NAMETABLE_ITEMS : std_logic_vector(31 downto 0);
|
|
signal BGB_VRAM_ADDR : std_logic_vector(15 downto 1);
|
|
signal BGB_VRAM32_DO : std_logic_vector(31 downto 0);
|
|
signal BGB_VRAM32_DO_REG : std_logic_vector(31 downto 0);
|
|
signal BGB_VRAM32_ACK : std_logic;
|
|
signal BGB_VRAM32_ACK_REG : std_logic;
|
|
signal BGB_SEL : std_logic;
|
|
signal BGB_VSRAM1_LATCH : std_logic_vector(10 downto 0);
|
|
signal BGB_VSRAM1_LAST_READ : std_logic_vector(10 downto 0);
|
|
|
|
signal BGB_MAPPING_EN : std_logic;
|
|
signal BGB_PATTERN_EN : std_logic;
|
|
signal BGB_ENABLE : std_logic;
|
|
|
|
-- BACKGROUND A
|
|
type bgac_t is (
|
|
BGAC_INIT,
|
|
BGAC_GET_VSCROLL,
|
|
BGAC_GET_VSCROLL2,
|
|
BGAC_GET_VSCROLL3,
|
|
BGAC_CALC_Y,
|
|
BGAC_CALC_BASE,
|
|
BGAC_BASE_RD,
|
|
BGAC_TILE_RD,
|
|
BGAC_LOOP,
|
|
BGAC_DONE
|
|
);
|
|
signal BGAC : bgac_t;
|
|
|
|
-- signal BGA_COLINFO : colinfo_t;
|
|
signal BGA_COLINFO_ADDR_A : std_logic_vector(8 downto 0);
|
|
signal BGA_COLINFO_ADDR_B : std_logic_vector(8 downto 0);
|
|
signal BGA_COLINFO_D_A : std_logic_vector(6 downto 0);
|
|
signal BGA_COLINFO_WE_A : std_logic;
|
|
signal BGA_COLINFO_WE_B : std_logic;
|
|
signal BGA_COLINFO_Q_B : std_logic_vector(6 downto 0);
|
|
|
|
signal BGA_X : std_logic_vector(9 downto 0);
|
|
signal BGA_POS : std_logic_vector(9 downto 0);
|
|
signal BGA_COL : std_logic_vector(6 downto 0);
|
|
signal BGA_Y : std_logic_vector(10 downto 0);
|
|
signal T_BGA_PRI : std_logic;
|
|
signal T_BGA_PAL : std_logic_vector(1 downto 0);
|
|
signal T_BGA_COLNO : std_logic_vector(3 downto 0);
|
|
signal BGA_BASE : std_logic_vector(15 downto 0);
|
|
signal BGA_TILEBASE : std_logic_vector(15 downto 0);
|
|
signal BGA_HF : std_logic;
|
|
|
|
signal BGA_NAMETABLE_ITEMS : std_logic_vector(31 downto 0);
|
|
signal BGA_VRAM_ADDR : std_logic_vector(15 downto 1);
|
|
signal BGA_VRAM32_DO : std_logic_vector(31 downto 0);
|
|
signal BGA_VRAM32_DO_REG : std_logic_vector(31 downto 0);
|
|
signal BGA_VRAM32_ACK : std_logic;
|
|
signal BGA_VRAM32_ACK_REG : std_logic;
|
|
signal BGA_SEL : std_logic;
|
|
signal BGA_VSRAM0_LATCH : std_logic_vector(10 downto 0);
|
|
signal BGA_VSRAM0_LAST_READ : std_logic_vector(10 downto 0);
|
|
|
|
signal WIN_V : std_logic;
|
|
signal WIN_H : std_logic;
|
|
|
|
signal BGA_MAPPING_EN : std_logic;
|
|
signal BGA_PATTERN_EN : std_logic;
|
|
signal BGA_ENABLE : std_logic;
|
|
----------------------------------------------------------------
|
|
-- SPRITE ENGINE
|
|
----------------------------------------------------------------
|
|
signal OBJ_MAX_FRAME : std_logic_vector(6 downto 0);
|
|
signal OBJ_MAX_LINE : std_logic_vector(5 downto 0);
|
|
|
|
signal OBJ_CACHE_ADDR_RD : std_logic_vector(6 downto 0);
|
|
signal OBJ_CACHE_ADDR_WR : std_logic_vector(6 downto 0);
|
|
signal OBJ_CACHE_D : std_logic_vector(31 downto 0);
|
|
signal OBJ_CACHE_Q : std_logic_vector(31 downto 0);
|
|
signal OBJ_CACHE_BE : std_logic_vector(3 downto 0);
|
|
signal OBJ_CACHE_WE : std_logic_vector(1 downto 0);
|
|
|
|
signal OBJ_VISINFO_ADDR_RD : std_logic_vector(5 downto 0);
|
|
signal OBJ_VISINFO_ADDR_WR : std_logic_vector(5 downto 0);
|
|
signal OBJ_VISINFO_D : std_logic_vector(6 downto 0);
|
|
signal OBJ_VISINFO_WE : std_logic;
|
|
signal OBJ_VISINFO_Q : std_logic_vector(6 downto 0);
|
|
|
|
signal OBJ_SPINFO_ADDR_RD : std_logic_vector(5 downto 0);
|
|
signal OBJ_SPINFO_ADDR_WR : std_logic_vector(5 downto 0);
|
|
signal OBJ_SPINFO_D : std_logic_vector(34 downto 0);
|
|
signal OBJ_SPINFO_WE : std_logic;
|
|
signal OBJ_SPINFO_Q : std_logic_vector(34 downto 0);
|
|
|
|
signal OBJ_COLINFO_CLK : std_logic;
|
|
signal OBJ_COLINFO_ADDR_A : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO_ADDR_B : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO_D_B : std_logic_vector(6 downto 0);
|
|
signal OBJ_COLINFO_WE_A : std_logic;
|
|
signal OBJ_COLINFO_WE_B : std_logic;
|
|
signal OBJ_COLINFO_Q_A : std_logic_vector(6 downto 0);
|
|
signal OBJ_COLINFO_ADDR_RD_SP3 : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO_ADDR_RD_REND : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO_ADDR_WR_SP3 : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO_ADDR_WR_REND : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO_WE_SP3 : std_logic;
|
|
signal OBJ_COLINFO_WE_REND : std_logic;
|
|
signal OBJ_COLINFO_D_SP3 : std_logic_vector(6 downto 0);
|
|
signal OBJ_COLINFO_D_REND : std_logic_vector(6 downto 0);
|
|
|
|
signal OBJ_COLINFO2_ADDR_RD : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO2_ADDR_WR : std_logic_vector(8 downto 0);
|
|
signal OBJ_COLINFO2_D : std_logic_vector(6 downto 0);
|
|
signal OBJ_COLINFO2_WE : std_logic;
|
|
signal OBJ_COLINFO2_Q : std_logic_vector(6 downto 0);
|
|
|
|
-- PART 1
|
|
signal SP1E_ACTIVATE : std_logic;
|
|
|
|
type sp1c_t is (
|
|
SP1C_INIT,
|
|
SP1C_Y_RD,
|
|
SP1C_Y_RD2,
|
|
SP1C_Y_RD3,
|
|
SP1C_Y_TST,
|
|
SP1C_SHOW,
|
|
SP1C_NEXT,
|
|
SP1C_DONE
|
|
);
|
|
signal SP1C : SP1C_t;
|
|
signal SP1_Y : std_logic_vector(8 downto 0);
|
|
signal SP1_EN : std_logic;
|
|
signal SP1_STEPS : std_logic_vector(6 downto 0);
|
|
|
|
signal OBJ_TOT : std_logic_vector(6 downto 0);
|
|
signal OBJ_NEXT : std_logic_vector(6 downto 0);
|
|
signal OBJ_NB : std_logic_vector(5 downto 0);
|
|
signal OBJ_Y_OFS : std_logic_vector(8 downto 0);
|
|
|
|
signal OBJ_VS1 : std_logic_vector(1 downto 0);
|
|
|
|
signal OBJ_CACHE_ADDR_RD_SP1 : std_logic_vector(6 downto 0);
|
|
|
|
-- PART 2
|
|
signal SP2E_ACTIVATE : std_logic;
|
|
|
|
type sp2c_t is (
|
|
SP2C_INIT,
|
|
SP2C_Y_RD,
|
|
SP2C_Y_RD2,
|
|
SP2C_Y_RD3,
|
|
SP2C_Y_RD4,
|
|
SP2C_RD,
|
|
SP2C_NEXT,
|
|
SP2C_DONE
|
|
);
|
|
signal SP2C : SP2C_t;
|
|
signal SP2_Y : std_logic_vector(8 downto 0);
|
|
signal SP2_EN : std_logic;
|
|
signal SP2_VRAM_ADDR : std_logic_vector(15 downto 1);
|
|
signal SP2_VRAM32_DO : std_logic_vector(31 downto 0);
|
|
signal SP2_VRAM32_DO_REG : std_logic_vector(31 downto 0);
|
|
signal SP2_VRAM32_ACK : std_logic;
|
|
signal SP2_SEL : std_logic;
|
|
|
|
signal OBJ_IDX : std_logic_vector(5 downto 0);
|
|
|
|
signal OBJ_CACHE_ADDR_RD_SP2 : std_logic_vector(6 downto 0);
|
|
|
|
-- PART 3
|
|
signal SP3E_ACTIVATE : std_logic;
|
|
|
|
type sp3c_t is (
|
|
SP3C_INIT,
|
|
SP3C_NEXT,
|
|
SP3C_TILE_RD,
|
|
SP3C_LOOP,
|
|
SP3C_PLOT,
|
|
SP3C_DONE
|
|
);
|
|
signal SP3C : SP3C_t;
|
|
|
|
signal SP3_VRAM_ADDR : std_logic_vector(15 downto 1);
|
|
signal SP3_VRAM32_DO : std_logic_vector(31 downto 0);
|
|
signal SP3_VRAM32_DO_REG: std_logic_vector(31 downto 0);
|
|
signal SP3_VRAM32_ACK : std_logic;
|
|
signal SP3_VRAM32_ACK_REG: std_logic;
|
|
signal SP3_SEL : std_logic;
|
|
|
|
signal OBJ_PIX : std_logic_vector(8 downto 0);
|
|
signal OBJ_NO : std_logic_vector(5 downto 0);
|
|
|
|
signal OBJ_LINK : std_logic_vector(6 downto 0);
|
|
|
|
signal OBJ_HS : std_logic_vector(1 downto 0);
|
|
signal OBJ_VS : std_logic_vector(1 downto 0);
|
|
signal OBJ_MASKED : std_logic;
|
|
signal OBJ_VALID_X : std_logic;
|
|
signal OBJ_DOT_OVERFLOW : std_logic;
|
|
signal OBJ_X_OFS : std_logic_vector(4 downto 0);
|
|
signal OBJ_PRI : std_logic;
|
|
signal OBJ_PAL : std_logic_vector(1 downto 0);
|
|
signal OBJ_HF : std_logic;
|
|
signal OBJ_POS : std_logic_vector(8 downto 0);
|
|
signal OBJ_TILEBASE : std_logic_vector(14 downto 0);
|
|
|
|
----------------------------------------------------------------
|
|
-- VIDEO OUTPUT
|
|
----------------------------------------------------------------
|
|
type pix_t is (
|
|
PIX_SHADOW,
|
|
PIX_NORMAL,
|
|
PIX_HIGHLIGHT
|
|
);
|
|
signal PIX_MODE : pix_t;
|
|
signal T_COLOR : std_logic_vector(15 downto 0);
|
|
|
|
signal FF_R : std_logic_vector(3 downto 0);
|
|
signal FF_G : std_logic_vector(3 downto 0);
|
|
signal FF_B : std_logic_vector(3 downto 0);
|
|
signal FF_VS : std_logic;
|
|
signal FF_HS : std_logic;
|
|
|
|
begin
|
|
|
|
bgb_ci : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 9,
|
|
databits => 7
|
|
)
|
|
port map(
|
|
address_a => BGB_COLINFO_ADDR_A,
|
|
address_b => BGB_COLINFO_ADDR_B,
|
|
clock => CLK,
|
|
data_a => BGB_COLINFO_D_A,
|
|
data_b => (others => '0'),
|
|
wren_a => BGB_COLINFO_WE_A,
|
|
wren_b => BGB_COLINFO_WE_B,
|
|
q_a => open,
|
|
q_b => BGB_COLINFO_Q_B
|
|
);
|
|
BGB_COLINFO_WE_B <= '0';
|
|
|
|
bga_ci : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 9,
|
|
databits => 7
|
|
)
|
|
port map(
|
|
address_a => BGA_COLINFO_ADDR_A,
|
|
address_b => BGA_COLINFO_ADDR_B,
|
|
clock => CLK,
|
|
data_a => BGA_COLINFO_D_A,
|
|
data_b => (others => '0'),
|
|
wren_a => BGA_COLINFO_WE_A,
|
|
wren_b => BGA_COLINFO_WE_B,
|
|
q_a => open,
|
|
q_b => BGA_COLINFO_Q_B
|
|
);
|
|
BGA_COLINFO_WE_B <= '0';
|
|
|
|
obj_ci : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 9,
|
|
databits => 7
|
|
)
|
|
port map(
|
|
address_a => OBJ_COLINFO_ADDR_A,
|
|
address_b => OBJ_COLINFO_ADDR_B,
|
|
clock => OBJ_COLINFO_CLK,
|
|
data_a => (others => '0'),
|
|
data_b => OBJ_COLINFO_D_B,
|
|
wren_a => OBJ_COLINFO_WE_A,
|
|
wren_b => OBJ_COLINFO_WE_B,
|
|
q_a => OBJ_COLINFO_Q_A,
|
|
q_b => open
|
|
);
|
|
OBJ_COLINFO_CLK <= not CLK;
|
|
OBJ_COLINFO_ADDR_A <= OBJ_COLINFO_ADDR_RD_SP3 when SP3C /= SP3C_DONE else OBJ_COLINFO_ADDR_RD_REND;
|
|
OBJ_COLINFO_ADDR_B <= OBJ_COLINFO_ADDR_WR_SP3 when SP3C /= SP3C_DONE else OBJ_COLINFO_ADDR_WR_REND;
|
|
OBJ_COLINFO_WE_A <= '0';
|
|
OBJ_COLINFO_WE_B <= OBJ_COLINFO_WE_SP3 when SP3C /= SP3C_DONE else OBJ_COLINFO_WE_REND;
|
|
OBJ_COLINFO_D_B <= OBJ_COLINFO_D_SP3 when SP3C /= SP3C_DONE else OBJ_COLINFO_D_REND;
|
|
|
|
obj_ci2 : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 9,
|
|
databits => 7
|
|
)
|
|
port map(
|
|
address_a => OBJ_COLINFO2_ADDR_RD,
|
|
address_b => OBJ_COLINFO2_ADDR_WR,
|
|
clock => CLK,
|
|
data_a => (others => '0'),
|
|
data_b => OBJ_COLINFO2_D,
|
|
wren_a => '0',
|
|
wren_b => OBJ_COLINFO2_WE,
|
|
q_a => OBJ_COLINFO2_Q,
|
|
q_b => open
|
|
);
|
|
|
|
obj_cache : entity work.obj_cache
|
|
port map(
|
|
clock => CLK,
|
|
rdaddress => OBJ_CACHE_ADDR_RD,
|
|
q => OBJ_CACHE_Q,
|
|
wraddress => OBJ_CACHE_ADDR_WR,
|
|
data => OBJ_CACHE_D,
|
|
wren => OBJ_CACHE_WE(1),
|
|
byteena_a => OBJ_CACHE_BE
|
|
);
|
|
|
|
OBJ_CACHE_ADDR_RD <= OBJ_CACHE_ADDR_RD_SP1 when SP1C /= SP1C_DONE else OBJ_CACHE_ADDR_RD_SP2;
|
|
|
|
obj_visinfo : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 6,
|
|
databits => 7
|
|
)
|
|
port map(
|
|
clock => CLK,
|
|
data_a => (others => '0'),
|
|
data_b => OBJ_VISINFO_D,
|
|
address_a => OBJ_VISINFO_ADDR_RD,
|
|
address_b => OBJ_VISINFO_ADDR_WR,
|
|
wren_a => '0',
|
|
wren_b => OBJ_VISINFO_WE,
|
|
q_a => OBJ_VISINFO_Q,
|
|
q_b => open
|
|
);
|
|
|
|
obj_spinfo : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 6,
|
|
databits => 35
|
|
)
|
|
port map(
|
|
clock => CLK,
|
|
data_a => (others => '0'),
|
|
data_b => OBJ_SPINFO_D,
|
|
address_a => OBJ_SPINFO_ADDR_RD,
|
|
address_b => OBJ_SPINFO_ADDR_WR,
|
|
wren_a => '0',
|
|
wren_b => OBJ_SPINFO_WE,
|
|
q_a => OBJ_SPINFO_Q,
|
|
q_b => open
|
|
);
|
|
|
|
cram : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 6,
|
|
databits => 9
|
|
)
|
|
port map(
|
|
address_a => CRAM_ADDR_A,
|
|
address_b => CRAM_ADDR_B,
|
|
clock => CLK,
|
|
data_a => CRAM_D_A,
|
|
data_b => (others => '0'),
|
|
wren_a => CRAM_WE_A,
|
|
wren_b => CRAM_WE_B,
|
|
q_a => CRAM_Q_A,
|
|
q_b => CRAM_Q_B
|
|
);
|
|
CRAM_WE_B <= '0';
|
|
|
|
vsram0 : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 5,
|
|
databits => 11
|
|
)
|
|
port map(
|
|
address_a => VSRAM0_ADDR_A,
|
|
address_b => VSRAM0_ADDR_B,
|
|
clock => CLK,
|
|
data_a => VSRAM0_D_A,
|
|
data_b => (others => '0'),
|
|
wren_a => VSRAM0_WE_A,
|
|
wren_b => VSRAM0_WE_B,
|
|
q_a => VSRAM0_Q_A,
|
|
q_b => VSRAM0_Q_B
|
|
);
|
|
VSRAM0_WE_B <= '0';
|
|
|
|
vsram1 : entity work.DualPortRAM
|
|
generic map (
|
|
addrbits => 5,
|
|
databits => 11
|
|
)
|
|
port map(
|
|
address_a => VSRAM1_ADDR_A,
|
|
address_b => VSRAM1_ADDR_B,
|
|
clock => CLK,
|
|
data_a => VSRAM1_D_A,
|
|
data_b => (others => '0'),
|
|
wren_a => VSRAM1_WE_A,
|
|
wren_b => VSRAM1_WE_B,
|
|
q_a => VSRAM1_Q_A,
|
|
q_b => VSRAM1_Q_B
|
|
);
|
|
VSRAM1_WE_B <= '0';
|
|
|
|
----------------------------------------------------------------
|
|
-- REGISTERS
|
|
----------------------------------------------------------------
|
|
ADDR_STEP <= REG(15);
|
|
H40 <= REG(12)(0);
|
|
RS0 <= REG(12)(7);
|
|
|
|
SHI <= REG(12)(3);
|
|
|
|
-- H40 <= '0';
|
|
V30 <= REG(1)(3);
|
|
-- V30 <= '0';
|
|
HSCR <= REG(11)(1 downto 0);
|
|
HSIZE <= REG(16)(1 downto 0);
|
|
-- VSIZE is limited to 64 if HSIZE is 64, to 32 if HSIZE is 128
|
|
VSIZE <= "01" when REG(16)(5 downto 4) = "11" and HSIZE = "01" else
|
|
"00" when HSIZE = "11" else
|
|
REG(16)(5 downto 4);
|
|
VSCR <= REG(11)(2);
|
|
|
|
WVP <= REG(18)(4 downto 0);
|
|
WDOWN <= REG(18)(7);
|
|
WHP <= REG(17)(4 downto 0);
|
|
WRIGT <= REG(17)(7);
|
|
|
|
BGCOL <= REG(7)(5 downto 0);
|
|
|
|
HIT <= REG(10);
|
|
IE1 <= REG(0)(4);
|
|
IE0 <= REG(1)(5);
|
|
|
|
M3 <= REG(0)(1);
|
|
|
|
DMA <= REG(1)(4);
|
|
M128 <= REG(1)(7);
|
|
|
|
LSM <= REG(12)(2 downto 1);
|
|
|
|
DE <= REG(1)(6);
|
|
M5 <= REG(1)(2);
|
|
|
|
-- Base addresses
|
|
HSCB <= REG(13)(5 downto 0);
|
|
NTBB <= REG(4)(2 downto 0);
|
|
NTWB <= REG(3)(5 downto 2)&(REG(3)(1) and not H40);
|
|
NTAB <= REG(2)(5 downto 3);
|
|
SATB <= REG(5)(7 downto 1)&(REG(5)(0) and not H40);
|
|
|
|
-- Read-only registers
|
|
ODD <= FIELD when LSM(0) = '1' else '0';
|
|
IN_DMA <= DMA_FILL or DMA_COPY or DMA_VBUS;
|
|
|
|
STATUS <= "111111" & FIFO_EMPTY & FIFO_FULL & VINT_TG68_PENDING & SOVR & SCOL & ODD & (IN_VBL or not DE) & IN_HBL & IN_DMA & PAL;
|
|
|
|
----------------------------------------------------------------
|
|
-- CPU INTERFACE
|
|
----------------------------------------------------------------
|
|
|
|
BGACK_N <= BGACK_N_REG;
|
|
|
|
----------------------------------------------------------------
|
|
-- VRAM CONTROLLER
|
|
----------------------------------------------------------------
|
|
vram32_req <= not vram32_req_reg when VMC32_NEXT /= VMC32_IDLE and RAM_REQ_PROGRESS = '0' and vram32_req_reg = vram32_ack else vram32_req_reg;
|
|
vram32_a <= vram32_a_next when VMC32_NEXT /= VMC32_IDLE and RAM_REQ_PROGRESS = '0' and vram32_req_reg = vram32_ack else vram32_a_reg;
|
|
|
|
-- Get the ack and data one cycle earlier
|
|
SP2_VRAM32_DO <= vram32_q when VMC32 = VMC32_SP2 else SP2_VRAM32_DO_REG;
|
|
SP3_VRAM32_DO <= vram32_q when VMC32 = VMC32_SP3 else SP3_VRAM32_DO_REG;
|
|
HSC_VRAM32_DO <= vram32_q when VMC32 = VMC32_HSC else HSC_VRAM32_DO_REG;
|
|
BGB_VRAM32_DO <= vram32_q when VMC32 = VMC32_BGB else BGB_VRAM32_DO_REG;
|
|
BGA_VRAM32_DO <= vram32_q when VMC32 = VMC32_BGA else BGA_VRAM32_DO_REG;
|
|
|
|
SP2_VRAM32_ACK <= '1' when VMC32 = VMC32_SP2 and vram32_req_reg = vram32_ack and RAM_REQ_PROGRESS = '1' else '0';
|
|
SP3_VRAM32_ACK <= '1' when VMC32 = VMC32_SP3 and vram32_req_reg = vram32_ack and RAM_REQ_PROGRESS = '1' else SP3_VRAM32_ACK_REG;
|
|
HSC_VRAM32_ACK <= '1' when VMC32 = VMC32_HSC and vram32_req_reg = vram32_ack and RAM_REQ_PROGRESS = '1' else '0';
|
|
BGB_VRAM32_ACK <= '1' when VMC32 = VMC32_BGB and vram32_req_reg = vram32_ack and RAM_REQ_PROGRESS = '1' else BGB_VRAM32_ACK_REG;
|
|
BGA_VRAM32_ACK <= '1' when VMC32 = VMC32_BGA and vram32_req_reg = vram32_ack and RAM_REQ_PROGRESS = '1' else BGA_VRAM32_ACK_REG;
|
|
|
|
VMC32_NEXT <= VMC32_SP3 when SP3_SEL = '1' and SP3_VRAM32_ACK_REG = '0' else
|
|
VMC32_SP2 when SP2_SEL = '1' else
|
|
VMC32_HSC when HSC_SEL = '1' else
|
|
VMC32_BGA when BGA_SEL = '1' and BGA_VRAM32_ACK_REG = '0' else
|
|
VMC32_BGB when BGB_SEL = '1' and BGB_VRAM32_ACK_REG = '0' else
|
|
VMC32_IDLE;
|
|
|
|
process( RST_N, CLK,
|
|
vram32_req_reg, vram32_ack, RAM_REQ_PROGRESS, VMC32_NEXT,
|
|
SP2_VRAM_ADDR, SP3_VRAM_ADDR, HSC_VRAM_ADDR, BGB_VRAM_ADDR, BGA_VRAM_ADDR)
|
|
begin
|
|
|
|
vram32_a_next <= (others => '0');
|
|
if vram32_req_reg = vram32_ack and RAM_REQ_PROGRESS = '0' then
|
|
case VMC32_NEXT is
|
|
when VMC32_IDLE =>
|
|
null;
|
|
when VMC32_SP2 =>
|
|
vram32_a_next <= SP2_VRAM_ADDR;
|
|
when VMC32_SP3 =>
|
|
vram32_a_next <= SP3_VRAM_ADDR;
|
|
when VMC32_HSC =>
|
|
vram32_a_next <= HSC_VRAM_ADDR;
|
|
when VMC32_BGB =>
|
|
vram32_a_next <= BGB_VRAM_ADDR;
|
|
when VMC32_BGA =>
|
|
vram32_a_next <= BGA_VRAM_ADDR;
|
|
end case;
|
|
end if;
|
|
|
|
if RST_N = '0' then
|
|
|
|
vram32_req_reg <= '0';
|
|
|
|
VMC32 <= VMC32_IDLE;
|
|
RAM_REQ_PROGRESS <= '0';
|
|
SP3_VRAM32_ACK_REG <= '0';
|
|
BGA_VRAM32_ACK_REG <= '0';
|
|
BGB_VRAM32_ACK_REG <= '0';
|
|
|
|
elsif rising_edge(CLK) then
|
|
if SP3_SEL = '0' then
|
|
SP3_VRAM32_ACK_REG <= '0';
|
|
end if;
|
|
if BGA_SEL = '0' then
|
|
BGA_VRAM32_ACK_REG <= '0';
|
|
end if;
|
|
if BGB_SEL = '0' then
|
|
BGB_VRAM32_ACK_REG <= '0';
|
|
end if;
|
|
|
|
if vram32_req_reg = vram32_ack then
|
|
if RAM_REQ_PROGRESS = '0' then
|
|
VMC32 <= VMC32_NEXT;
|
|
if VMC32_NEXT /= VMC32_IDLE then
|
|
vram32_a_reg <= vram32_a_next;
|
|
vram32_req_reg <= not vram32_req_reg;
|
|
RAM_REQ_PROGRESS <= '1';
|
|
end if;
|
|
else
|
|
case VMC32 is
|
|
when VMC32_IDLE =>
|
|
null;
|
|
when VMC32_SP2 =>
|
|
SP2_VRAM32_DO_REG <= vram32_q;
|
|
when VMC32_SP3 =>
|
|
SP3_VRAM32_DO_REG <= vram32_q;
|
|
SP3_VRAM32_ACK_REG <= '1';
|
|
when VMC32_HSC =>
|
|
HSC_VRAM32_DO_REG <= vram32_q;
|
|
when VMC32_BGB =>
|
|
BGB_VRAM32_DO_REG <= vram32_q;
|
|
BGB_VRAM32_ACK_REG <= '1';
|
|
when VMC32_BGA =>
|
|
BGA_VRAM32_DO_REG <= vram32_q;
|
|
BGA_VRAM32_ACK_REG <= '1';
|
|
end case;
|
|
RAM_REQ_PROGRESS <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- 16 bit interface for data transfer
|
|
|
|
vram_req <= DT_VRAM_SEL;
|
|
vram_d <= DT_VRAM_DI when M128 = '0' else DT_VRAM_DI(7 downto 0) & DT_VRAM_DI(7 downto 0);
|
|
vram_we <= not DT_VRAM_RNW;
|
|
vram_u_n <= (DT_VRAM_UDS_N or M128) and (not vram_a_reg(1) or not M128);
|
|
vram_l_n <= (DT_VRAM_LDS_N or M128) and (vram_a_reg(1) or not M128);
|
|
vram_a <= vram_a_reg(15 downto 1) when M128 = '0' else vram_a_reg(16 downto 11) & vram_a_reg(9 downto 2) & vram_a_reg(10);
|
|
vram_a_reg <= DT_VRAM_ADDR;
|
|
early_ack_dt <= '0' when DT_VRAM_SEL=vram_ack else '1';
|
|
DT_VRAM_DO <= vram_q;
|
|
|
|
----------------------------------------------------------------
|
|
-- HSCROLL READ
|
|
----------------------------------------------------------------
|
|
process (RST_N, CLK) begin
|
|
if RST_N = '0' then
|
|
HSC_SEL <= '0';
|
|
elsif rising_edge(CLK) then
|
|
if V_ACTIVE = '1' and HV_HCNT = HSCROLL_READ and HV_PIXDIV = 0 then
|
|
|
|
case HSCR is -- Horizontal scroll mode
|
|
when "00" =>
|
|
HSC_VRAM_ADDR <= HSCB & "000000000";
|
|
when "01" =>
|
|
HSC_VRAM_ADDR <= HSCB & "00000" & Y(2 downto 0) & '0';
|
|
when "10" =>
|
|
HSC_VRAM_ADDR <= HSCB & Y(7 downto 3) & "0000";
|
|
when "11" =>
|
|
HSC_VRAM_ADDR <= HSCB & Y & '0';
|
|
when others => null;
|
|
end case;
|
|
HSC_SEL <= '1';
|
|
elsif HSC_VRAM32_ACK = '1' then
|
|
HSC_SEL <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
----------------------------------------------------------------
|
|
-- BACKGROUND B RENDERING
|
|
----------------------------------------------------------------
|
|
process( RST_N, CLK )
|
|
variable V_BGB_XSTART : std_logic_vector(9 downto 0);
|
|
variable V_BGB_BASE : std_logic_vector(15 downto 0);
|
|
variable bgb_nametable_item : std_logic_vector(15 downto 0);
|
|
variable vscroll_mask : std_logic_vector(10 downto 0);
|
|
variable hscroll_mask : std_logic_vector(9 downto 0);
|
|
variable vscroll_val : std_logic_vector(10 downto 0);
|
|
variable vscroll_index : std_logic_vector(4 downto 0);
|
|
variable y_cells : std_logic_vector(6 downto 0);
|
|
|
|
-- synthesis translate_off
|
|
file F : text open write_mode is "bgb_dbg.out";
|
|
variable L : line;
|
|
-- synthesis translate_on
|
|
begin
|
|
if RST_N = '0' then
|
|
BGB_SEL <= '0';
|
|
BGB_ENABLE <= '1';
|
|
BGBC <= BGBC_DONE;
|
|
elsif rising_edge(CLK) then
|
|
case BGBC is
|
|
when BGBC_DONE =>
|
|
VSRAM1_ADDR_B <= (others => '0');
|
|
if HV_HCNT = H_INT_POS and HV_PIXDIV = 0 and VSCR = '0' then
|
|
BGB_VSRAM1_LATCH <= VSRAM1_Q_B;
|
|
BGB_VSRAM1_LAST_READ <= VSRAM1_Q_B;
|
|
end if;
|
|
BGB_SEL <= '0';
|
|
BGB_COLINFO_WE_A <= '0';
|
|
BGB_COLINFO_ADDR_A <= (others => '0');
|
|
if BGEN_ACTIVATE = '1' then
|
|
BGBC <= BGBC_INIT;
|
|
end if;
|
|
|
|
when BGBC_INIT =>
|
|
if HSIZE = "10" then
|
|
-- illegal mode, 32x1
|
|
hscroll_mask := "0011111111";
|
|
vscroll_mask := "00000000111";
|
|
else
|
|
hscroll_mask := (HSIZE & "11111111");
|
|
vscroll_mask := '0' & (VSIZE & "11111111");
|
|
end if;
|
|
|
|
if LSM = "11" then
|
|
vscroll_mask := vscroll_mask(9 downto 0) & '1';
|
|
end if;
|
|
|
|
V_BGB_XSTART := "0000000000" - HSC_VRAM32_DO(25 downto 16);
|
|
if V_BGB_XSTART(3 downto 0) = "0000" then
|
|
V_BGB_XSTART := V_BGB_XSTART - 16;
|
|
BGB_POS <= "1111110000";
|
|
else
|
|
BGB_POS <= "0000000000" - ( "000000" & V_BGB_XSTART(3 downto 0) );
|
|
end if;
|
|
BGB_X <= ( V_BGB_XSTART(9 downto 4) & "0000" ) and hscroll_mask;
|
|
BGB_COL <= "1111110"; -- -2
|
|
BGBC <= BGBC_GET_VSCROLL;
|
|
|
|
when BGBC_GET_VSCROLL =>
|
|
BGB_COLINFO_WE_A <= '0';
|
|
if BGB_COL(5 downto 1) <= 19 then
|
|
VSRAM1_ADDR_B <= BGB_COL(5 downto 1);
|
|
else
|
|
VSRAM1_ADDR_B <= (others => '0');
|
|
end if;
|
|
BGBC <= BGBC_GET_VSCROLL2;
|
|
|
|
when BGBC_GET_VSCROLL2 =>
|
|
BGBC <= BGBC_GET_VSCROLL3;
|
|
|
|
when BGBC_GET_VSCROLL3 =>
|
|
if VSCR = '1' then
|
|
if BGB_COL(5 downto 1) <= 19 then
|
|
BGB_VSRAM1_LATCH <= VSRAM1_Q_B;
|
|
BGB_VSRAM1_LAST_READ <= VSRAM1_Q_B;
|
|
elsif H40 = '0' then
|
|
BGB_VSRAM1_LATCH <= (others => '0');
|
|
elsif VSCROLL_BUG = '1' then
|
|
-- partial column gets the last read values AND'ed in H40 ("left column scroll bug")
|
|
BGB_VSRAM1_LATCH <= BGB_VSRAM1_LAST_READ and BGA_VSRAM0_LAST_READ;
|
|
else
|
|
-- using VSRAM(1) sometimes looks better (Gynoug)
|
|
BGB_VSRAM1_LATCH <= VSRAM1_Q_B;
|
|
end if;
|
|
end if;
|
|
BGBC <= BGBC_CALC_Y;
|
|
|
|
when BGBC_CALC_Y =>
|
|
-- synthesis translate_off
|
|
write(L, string'("BGB COL = "));
|
|
hwrite(L, "0" & BGB_COL);
|
|
write(L, string'(" BGB X = "));
|
|
hwrite(L, "000000" & BGB_X(9 downto 0));
|
|
write(L, string'(" POS="));
|
|
hwrite(L, "000000" & BGB_POS(9 downto 0));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
if LSM = "11" then
|
|
vscroll_val := BGB_VSRAM1_LATCH(10 downto 0);
|
|
else
|
|
vscroll_val := '0' & BGB_VSRAM1_LATCH(9 downto 0);
|
|
end if;
|
|
BGB_Y <= (BG_Y + vscroll_val) and vscroll_mask;
|
|
BGBC <= BGBC_CALC_BASE;
|
|
|
|
when BGBC_CALC_BASE =>
|
|
if BGB_MAPPING_EN = '1' then
|
|
-- BGB mapping slot
|
|
if LSM = "11" then
|
|
y_cells := BGB_Y(10 downto 4);
|
|
else
|
|
y_cells := BGB_Y(9 downto 3);
|
|
end if;
|
|
case HSIZE is
|
|
when "00"|"10" => -- HS 32 cells
|
|
V_BGB_BASE := (NTBB & "0000000000000") + (BGB_X(9 downto 3) & "0") + (y_cells & "00000" & "0");
|
|
when "01" => -- HS 64 cells
|
|
V_BGB_BASE := (NTBB & "0000000000000") + (BGB_X(9 downto 3) & "0") + (y_cells & "000000" & "0");
|
|
when "11" => -- HS 128 cells
|
|
V_BGB_BASE := (NTBB & "0000000000000") + (BGB_X(9 downto 3) & "0") + (y_cells & "0000000" & "0");
|
|
when others => null;
|
|
end case;
|
|
BGB_VRAM_ADDR <= V_BGB_BASE(15 downto 1);
|
|
BGB_ENABLE <= DE;
|
|
if DE = '1' then
|
|
BGB_SEL <= '1';
|
|
BGBC <= BGBC_BASE_RD;
|
|
else
|
|
BGBC <= BGBC_LOOP;
|
|
end if;
|
|
end if;
|
|
|
|
when BGBC_BASE_RD =>
|
|
if BGB_VRAM32_ACK = '1' then
|
|
-- synthesis translate_off
|
|
write(L, string'("BGB BASE_RD Y="));
|
|
hwrite(L, "000000" & BGB_Y(9 downto 0));
|
|
write(L, string'(" X="));
|
|
hwrite(L, "000000" & BGB_X(9 downto 0));
|
|
write(L, string'(" POS="));
|
|
hwrite(L, "000000" & BGB_POS(9 downto 0));
|
|
write(L, string'(" BASE_RD ["));
|
|
hwrite(L, BGB_VRAM_ADDR & '0');
|
|
write(L, string'("] = ["));
|
|
hwrite(L, BGB_VRAM32_DO);
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
BGB_SEL <= '0';
|
|
BGB_NAMETABLE_ITEMS <= BGB_VRAM32_DO;
|
|
BGBC <= BGBC_TILE_RD;
|
|
end if;
|
|
|
|
when BGBC_TILE_RD =>
|
|
-- BGB pattern slot
|
|
BGB_COLINFO_WE_A <= '0';
|
|
|
|
if BGB_X(3) = '0' then
|
|
bgb_nametable_item := BGB_NAMETABLE_ITEMS(15 downto 0);
|
|
else
|
|
bgb_nametable_item := BGB_NAMETABLE_ITEMS(31 downto 16);
|
|
end if;
|
|
T_BGB_PRI <= bgb_nametable_item(15);
|
|
T_BGB_PAL <= bgb_nametable_item(14 downto 13);
|
|
BGB_HF <= bgb_nametable_item(11);
|
|
if LSM = "11" then
|
|
if bgb_nametable_item(12) = '1' then -- VF
|
|
BGB_VRAM_ADDR <= bgb_nametable_item(9 downto 0) & not(BGB_Y(3 downto 0)) & "0";
|
|
else
|
|
BGB_VRAM_ADDR <= bgb_nametable_item(9 downto 0) & BGB_Y(3 downto 0) & "0";
|
|
end if;
|
|
else
|
|
if bgb_nametable_item(12) = '1' then -- VF
|
|
BGB_VRAM_ADDR <= bgb_nametable_item(10 downto 0) & not(BGB_Y(2 downto 0)) & "0";
|
|
else
|
|
BGB_VRAM_ADDR <= bgb_nametable_item(10 downto 0) & BGB_Y(2 downto 0) & "0";
|
|
end if;
|
|
end if;
|
|
|
|
if BGB_ENABLE = '1' then
|
|
BGB_SEL <= '1';
|
|
end if;
|
|
BGBC <= BGBC_LOOP;
|
|
|
|
when BGBC_LOOP =>
|
|
if BGB_VRAM32_ACK = '1' or BGB_SEL = '0' or BGB_ENABLE = '0' then
|
|
BGB_SEL <= '0';
|
|
|
|
BGB_COLINFO_ADDR_A <= BGB_POS(8 downto 0);
|
|
BGB_COLINFO_WE_A <= '1';
|
|
case BGB_X(2 downto 0) is
|
|
when "100" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO( 3 downto 0);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(31 downto 28);
|
|
end if;
|
|
when "101" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO( 7 downto 4);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(27 downto 24);
|
|
end if;
|
|
when "110" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(11 downto 8);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(23 downto 20);
|
|
end if;
|
|
when "111" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(15 downto 12);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(19 downto 16);
|
|
end if;
|
|
when "000" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(19 downto 16);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(15 downto 12);
|
|
end if;
|
|
when "001" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(23 downto 20);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(11 downto 8);
|
|
end if;
|
|
when "010" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(27 downto 24);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO( 7 downto 4);
|
|
end if;
|
|
when "011" =>
|
|
if BGB_HF = '1' then
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO(31 downto 28);
|
|
else
|
|
BGB_COLINFO_D_A <= T_BGB_PRI & T_BGB_PAL & BGB_VRAM32_DO( 3 downto 0);
|
|
end if;
|
|
when others => null;
|
|
end case;
|
|
|
|
if BGB_ENABLE = '0' or DE = '0' then
|
|
BGB_COLINFO_D_A <= '0' & BGCOL;
|
|
end if;
|
|
|
|
BGB_X <= (BGB_X + 1) and hscroll_mask;
|
|
BGB_POS <= BGB_POS + 1;
|
|
if BGB_X(2 downto 0) = "111" then
|
|
BGB_COL <= BGB_COL + 1;
|
|
if (H40 = '0' and BGB_COL = 31) or (H40 = '1' and BGB_COL = 39) then
|
|
BGBC <= BGBC_DONE;
|
|
elsif BGB_X(3) = '0' then
|
|
BGBC <= BGBC_TILE_RD;
|
|
else
|
|
BGBC <= BGBC_GET_VSCROLL;
|
|
end if;
|
|
else
|
|
BGBC <= BGBC_LOOP;
|
|
end if;
|
|
end if;
|
|
when others => -- BGBC_DONE
|
|
BGB_SEL <= '0';
|
|
BGB_COLINFO_WE_A <= '0';
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
----------------------------------------------------------------
|
|
-- BACKGROUND A RENDERING
|
|
----------------------------------------------------------------
|
|
process( RST_N, CLK )
|
|
variable V_BGA_XSTART : std_logic_vector(9 downto 0);
|
|
variable V_BGA_XBASE : std_logic_vector(15 downto 0);
|
|
variable V_BGA_BASE : std_logic_vector(15 downto 0);
|
|
variable bga_pos_next : std_logic_vector(9 downto 0);
|
|
variable bga_nametable_item : std_logic_vector(15 downto 0);
|
|
variable tile_pos : std_logic_vector(3 downto 0);
|
|
variable vscroll_mask : std_logic_vector(10 downto 0);
|
|
variable hscroll_mask : std_logic_vector(9 downto 0);
|
|
variable vscroll_val : std_logic_vector(10 downto 0);
|
|
variable vscroll_index : std_logic_vector(4 downto 0);
|
|
variable y_cells : std_logic_vector(6 downto 0);
|
|
-- synthesis translate_off
|
|
file F : text open write_mode is "bga_dbg.out";
|
|
variable L : line;
|
|
-- synthesis translate_on
|
|
begin
|
|
if RST_N = '0' then
|
|
BGA_SEL <= '0';
|
|
BGAC <= BGAC_DONE;
|
|
BGA_ENABLE <= '1';
|
|
elsif rising_edge(CLK) then
|
|
case BGAC is
|
|
when BGAC_DONE =>
|
|
VSRAM0_ADDR_B <= (others => '0');
|
|
if HV_HCNT = H_INT_POS and HV_PIXDIV = 0 then
|
|
if VSCR = '0' then
|
|
BGA_VSRAM0_LATCH <= VSRAM0_Q_B;
|
|
BGA_VSRAM0_LAST_READ <= VSRAM0_Q_B;
|
|
end if;
|
|
WRIGT_LATCH <= WRIGT;
|
|
WHP_LATCH <= WHP;
|
|
end if;
|
|
BGA_SEL <= '0';
|
|
BGA_COLINFO_ADDR_A <= (others => '0');
|
|
BGA_COLINFO_WE_A <= '0';
|
|
if BGEN_ACTIVATE = '1' then
|
|
BGAC <= BGAC_INIT;
|
|
end if;
|
|
when BGAC_INIT =>
|
|
if HSIZE = "10" then
|
|
-- illegal mode, 32x1
|
|
hscroll_mask := "0011111111";
|
|
vscroll_mask := "00000000111";
|
|
else
|
|
hscroll_mask := (HSIZE & "11111111");
|
|
vscroll_mask := '0' & (VSIZE & "11111111");
|
|
end if;
|
|
|
|
if LSM = "11" then
|
|
vscroll_mask := vscroll_mask(9 downto 0) & '1';
|
|
end if;
|
|
|
|
if Y(7 downto 3) < WVP then
|
|
WIN_V <= not WDOWN;
|
|
else
|
|
WIN_V <= WDOWN;
|
|
end if;
|
|
|
|
if WHP_LATCH = "00000" then
|
|
WIN_H <= WRIGT_LATCH;
|
|
else
|
|
WIN_H <= not WRIGT_LATCH;
|
|
end if;
|
|
|
|
V_BGA_XSTART := "0000000000" - HSC_VRAM32_DO(9 downto 0);
|
|
if V_BGA_XSTART(3 downto 0) = "0000" then
|
|
V_BGA_XSTART := V_BGA_XSTART - 16;
|
|
BGA_POS <= "1111110000";
|
|
else
|
|
BGA_POS <= "0000000000" - ( "000000" & V_BGA_XSTART(3 downto 0) );
|
|
end if;
|
|
|
|
BGA_X <= ( V_BGA_XSTART(9 downto 4) & "0000" ) and hscroll_mask;
|
|
BGA_COL <= "1111110"; -- -2
|
|
BGAC <= BGAC_GET_VSCROLL;
|
|
|
|
when BGAC_GET_VSCROLL =>
|
|
BGA_COLINFO_WE_A <= '0';
|
|
|
|
if BGA_COL(5 downto 1) <= 19 then
|
|
VSRAM0_ADDR_B <= BGA_COL(5 downto 1);
|
|
else
|
|
VSRAM0_ADDR_B <= (others => '0');
|
|
end if;
|
|
BGAC <= BGAC_GET_VSCROLL2;
|
|
|
|
when BGAC_GET_VSCROLL2 =>
|
|
BGAC <= BGAC_GET_VSCROLL3;
|
|
|
|
when BGAC_GET_VSCROLL3 =>
|
|
if VSCR = '1' then
|
|
if BGA_COL(5 downto 1) <= 19 then
|
|
BGA_VSRAM0_LATCH <= VSRAM0_Q_B;
|
|
BGA_VSRAM0_LAST_READ <= VSRAM0_Q_B;
|
|
elsif H40 = '0' then
|
|
BGA_VSRAM0_LATCH <= (others => '0');
|
|
elsif VSCROLL_BUG = '1' then
|
|
-- partial column gets the last read values AND'ed in H40 ("left column scroll bug")
|
|
BGA_VSRAM0_LATCH <= BGA_VSRAM0_LAST_READ and BGB_VSRAM1_LAST_READ;
|
|
else
|
|
-- using VSRAM(0) sometimes looks better (Gynoug)
|
|
BGA_VSRAM0_LATCH <= VSRAM0_Q_B;
|
|
end if;
|
|
end if;
|
|
BGAC <= BGAC_CALC_Y;
|
|
|
|
when BGAC_CALC_Y =>
|
|
if WIN_H = '1' or WIN_V = '1' then
|
|
BGA_Y <= "00" & BG_Y;
|
|
else
|
|
if LSM = "11" then
|
|
vscroll_val := BGA_VSRAM0_LATCH(10 downto 0);
|
|
else
|
|
vscroll_val := '0' & BGA_VSRAM0_LATCH(9 downto 0);
|
|
end if;
|
|
BGA_Y <= (BG_Y + vscroll_val) and vscroll_mask;
|
|
end if;
|
|
BGAC <= BGAC_CALC_BASE;
|
|
|
|
when BGAC_CALC_BASE =>
|
|
if BGA_MAPPING_EN = '1' then
|
|
-- BGA mapping slot
|
|
if LSM = "11" then
|
|
y_cells := BGA_Y(10 downto 4);
|
|
else
|
|
y_cells := BGA_Y(9 downto 3);
|
|
end if;
|
|
|
|
if WIN_H = '1' or WIN_V = '1' then
|
|
V_BGA_XBASE := (NTWB & "00000000000") + (BGA_POS(9 downto 3) & "0");
|
|
if H40 = '0' then -- WIN is 32 tiles wide in H32 mode
|
|
V_BGA_BASE := V_BGA_XBASE + (y_cells & "00000" & "0");
|
|
else -- WIN is 64 tiles wide in H40 mode
|
|
V_BGA_BASE := V_BGA_XBASE + (y_cells & "000000" & "0");
|
|
end if;
|
|
else
|
|
V_BGA_XBASE := (NTAB & "0000000000000") + (BGA_X(9 downto 3) & "0");
|
|
case HSIZE is
|
|
when "00"|"10" => -- HS 32 cells
|
|
V_BGA_BASE := V_BGA_XBASE + (y_cells & "00000" & "0");
|
|
when "01" => -- HS 64 cells
|
|
V_BGA_BASE := V_BGA_XBASE + (y_cells & "000000" & "0");
|
|
when "11" => -- HS 128 cells
|
|
V_BGA_BASE := V_BGA_XBASE + (y_cells & "0000000" & "0");
|
|
when others => null;
|
|
end case;
|
|
end if;
|
|
|
|
BGA_VRAM_ADDR <= V_BGA_BASE(15 downto 1);
|
|
BGA_ENABLE <= DE;
|
|
if DE = '1' then
|
|
BGA_SEL <= '1';
|
|
BGAC <= BGAC_BASE_RD;
|
|
else
|
|
BGAC <= BGAC_LOOP;
|
|
end if;
|
|
end if;
|
|
|
|
when BGAC_BASE_RD =>
|
|
if BGA_VRAM32_ACK = '1' then
|
|
-- synthesis translate_off
|
|
write(L, string'("BGA BASE_RD Y="));
|
|
hwrite(L, "000000" & BGA_Y(9 downto 0));
|
|
write(L, string'(" X="));
|
|
hwrite(L, "000000" & BGA_X(9 downto 0));
|
|
write(L, string'(" POS="));
|
|
hwrite(L, "000000" & BGA_POS(9 downto 0));
|
|
write(L, string'(" BASE_RD ["));
|
|
hwrite(L, BGA_VRAM_ADDR & '0');
|
|
write(L, string'("] = ["));
|
|
hwrite(L, BGA_VRAM32_DO);
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
BGA_SEL <= '0';
|
|
BGA_NAMETABLE_ITEMS <= BGA_VRAM32_DO;
|
|
BGAC <= BGAC_TILE_RD;
|
|
end if;
|
|
|
|
when BGAC_TILE_RD =>
|
|
-- BGA pattern slot
|
|
BGA_COLINFO_WE_A <= '0';
|
|
|
|
if ((WIN_H = '1' or WIN_V = '1') and BGA_POS(3) = '0') or
|
|
(WIN_H = '0' and WIN_V = '0' and BGA_X(3) = '0') then
|
|
bga_nametable_item := BGA_NAMETABLE_ITEMS(15 downto 0);
|
|
else
|
|
bga_nametable_item := BGA_NAMETABLE_ITEMS(31 downto 16);
|
|
end if;
|
|
|
|
T_BGA_PRI <= bga_nametable_item(15);
|
|
T_BGA_PAL <= bga_nametable_item(14 downto 13);
|
|
BGA_HF <= bga_nametable_item(11);
|
|
if LSM = "11" then
|
|
if bga_nametable_item(12) = '1' then -- VF
|
|
BGA_VRAM_ADDR <= bga_nametable_item(9 downto 0) & not(BGA_Y(3 downto 0)) & "0";
|
|
else
|
|
BGA_VRAM_ADDR <= bga_nametable_item(9 downto 0) & BGA_Y(3 downto 0) & "0";
|
|
end if;
|
|
else
|
|
if bga_nametable_item(12) = '1' then -- VF
|
|
BGA_VRAM_ADDR <= bga_nametable_item(10 downto 0) & not(BGA_Y(2 downto 0)) & "0";
|
|
else
|
|
BGA_VRAM_ADDR <= bga_nametable_item(10 downto 0) & BGA_Y(2 downto 0) & "0";
|
|
end if;
|
|
end if;
|
|
|
|
if BGA_ENABLE = '1' then
|
|
BGA_SEL <= '1';
|
|
end if;
|
|
BGAC <= BGAC_LOOP;
|
|
|
|
when BGAC_LOOP =>
|
|
if BGA_VRAM32_ACK = '1' or BGA_SEL = '0' or BGA_ENABLE = '0' then
|
|
BGA_SEL <= '0';
|
|
|
|
if SVP_QUIRK = '0' or BG_Y /= 223 then
|
|
BGA_COLINFO_WE_A <= '1';
|
|
end if;
|
|
|
|
BGA_COLINFO_ADDR_A <= BGA_POS(8 downto 0);
|
|
if WIN_H = '1' or WIN_V = '1' then
|
|
tile_pos := BGA_POS(3 downto 0);
|
|
else
|
|
tile_pos := BGA_X(3 downto 0);
|
|
end if;
|
|
case tile_pos(2 downto 0) is
|
|
when "100" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO( 3 downto 0);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(31 downto 28);
|
|
end if;
|
|
when "101" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO( 7 downto 4);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(27 downto 24);
|
|
end if;
|
|
when "110" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(11 downto 8);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(23 downto 20);
|
|
end if;
|
|
when "111" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(15 downto 12);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(19 downto 16);
|
|
end if;
|
|
when "000" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(19 downto 16);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(15 downto 12);
|
|
end if;
|
|
when "001" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(23 downto 20);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(11 downto 8);
|
|
end if;
|
|
when "010" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(27 downto 24);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO( 7 downto 4);
|
|
end if;
|
|
when "011" =>
|
|
if BGA_HF = '1' then
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO(31 downto 28);
|
|
else
|
|
BGA_COLINFO_D_A <= T_BGA_PRI & T_BGA_PAL & BGA_VRAM32_DO( 3 downto 0);
|
|
end if;
|
|
when others => null;
|
|
end case;
|
|
|
|
if BGA_ENABLE = '0' or DE = '0' then
|
|
BGA_COLINFO_D_A <= '0' & BGCOL;
|
|
end if;
|
|
|
|
BGA_X <= (BGA_X + 1) and hscroll_mask;
|
|
bga_pos_next := BGA_POS + 1;
|
|
BGA_POS <= bga_pos_next;
|
|
if tile_pos(2 downto 0) = "111" then
|
|
if tile_pos(3) = '0' then
|
|
BGAC <= BGAC_TILE_RD;
|
|
else
|
|
BGAC <= BGAC_GET_VSCROLL;
|
|
end if;
|
|
else
|
|
BGAC <= BGAC_LOOP;
|
|
end if;
|
|
|
|
if WIN_H = '1' and WRIGT_LATCH = '0' and BGA_POS(3 downto 0) = "1111" and bga_pos_next(8 downto 4) = WHP_LATCH
|
|
then
|
|
-- window on the left side ends, but not neccessarily on a scroll boundary,
|
|
-- when it continues to draw a wrong tile ("left window bug")
|
|
WIN_H <= '0';
|
|
if WIN_V = '0' and BGA_X(3 downto 0) /= "1111" then
|
|
BGAC <= BGAC_LOOP;
|
|
end if;
|
|
elsif WIN_H = '0' and WRIGT_LATCH = '1' and BGA_POS(3 downto 0) = "1111" and bga_pos_next(8 downto 4) = WHP_LATCH
|
|
then
|
|
-- window on the right side starts, cancel rendering the current tile
|
|
WIN_H <= '1';
|
|
BGAC <= BGAC_GET_VSCROLL;
|
|
end if;
|
|
|
|
if BGA_X(2 downto 0) = "111" then
|
|
BGA_COL <= BGA_COL + 1;
|
|
if (H40 = '0' and BGA_COL = 31) or (H40 = '1' and BGA_COL = 39) then
|
|
BGAC <= BGAC_DONE;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when others => -- BGAC_DONE
|
|
BGA_SEL <= '0';
|
|
BGA_COLINFO_WE_A <= '0';
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
----------------------------------------------------------------
|
|
-- SPRITE ENGINE
|
|
----------------------------------------------------------------
|
|
OBJ_MAX_FRAME <= conv_std_logic_vector(OBJ_MAX_FRAME_H40, 7) when H40 = '1' else
|
|
conv_std_logic_vector(OBJ_MAX_FRAME_H32, 7);
|
|
|
|
OBJ_MAX_LINE <= conv_std_logic_vector(OBJ_MAX_LINE_H40, 6) when H40 = '1' and OBJ_LIMIT_HIGH_EN = '0' else
|
|
conv_std_logic_vector(OBJ_MAX_LINE_H40_HIGH, 6) when H40 = '1' and OBJ_LIMIT_HIGH_EN = '1' else
|
|
conv_std_logic_vector(OBJ_MAX_LINE_H32, 6) when H40 = '0' and OBJ_LIMIT_HIGH_EN = '0' else
|
|
conv_std_logic_vector(OBJ_MAX_LINE_H32_HIGH, 6) when H40 = '0' and OBJ_LIMIT_HIGH_EN = '1';
|
|
|
|
-- Write-through cache for Y, Link and size fields
|
|
process( RST_N, CLK )
|
|
variable cache_addr: std_logic_vector(13 downto 0);
|
|
begin
|
|
if RST_N = '0' then
|
|
|
|
OBJ_CACHE_ADDR_WR <= (others => '0');
|
|
OBJ_CACHE_WE <= "00";
|
|
|
|
elsif rising_edge(CLK) then
|
|
|
|
OBJ_CACHE_WE <= OBJ_CACHE_WE(0) & '0';
|
|
|
|
cache_addr := DT_VRAM_ADDR(16 downto 3) - (SATB & "000000");
|
|
DT_VRAM_SEL_D <= DT_VRAM_SEL;
|
|
if DT_VRAM_SEL_D /= DT_VRAM_SEL and DT_VRAM_RNW = '0' and
|
|
DT_VRAM_ADDR(2) = '0' and cache_addr < OBJ_MAX_FRAME
|
|
then
|
|
OBJ_CACHE_ADDR_WR <= cache_addr(6 downto 0);
|
|
OBJ_CACHE_D <= DT_VRAM_DI & DT_VRAM_DI;
|
|
OBJ_CACHE_BE(3) <= DT_VRAM_ADDR(1) and not DT_VRAM_UDS_N;
|
|
OBJ_CACHE_BE(2) <= DT_VRAM_ADDR(1) and not DT_VRAM_LDS_N;
|
|
OBJ_CACHE_BE(1) <= not DT_VRAM_ADDR(1) and not DT_VRAM_UDS_N;
|
|
OBJ_CACHE_BE(0) <= not DT_VRAM_ADDR(1) and not DT_VRAM_LDS_N;
|
|
OBJ_CACHE_WE <= "01";
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
----------------------------------------------------------------
|
|
-- SPRITE ENGINE - PART ONE
|
|
------------------------------------------------------------------
|
|
-- determine the first 16/20 visible sprites
|
|
process( RST_N, CLK )
|
|
-- synthesis translate_off
|
|
file F : text open write_mode is "sp1_dbg.out";
|
|
variable L : line;
|
|
-- synthesis translate_on
|
|
variable y_offset: std_logic_vector(9 downto 0);
|
|
begin
|
|
if RST_N = '0' then
|
|
SP1C <= SP1C_DONE;
|
|
OBJ_CACHE_ADDR_RD_SP1 <= (others => '0');
|
|
|
|
OBJ_VISINFO_ADDR_WR <= (others => '0');
|
|
|
|
elsif rising_edge(CLK) then
|
|
|
|
case SP1C is
|
|
when SP1C_INIT =>
|
|
SP1_Y <= PRE_Y; -- Latch the current PRE_Y value
|
|
OBJ_TOT <= (others => '0');
|
|
OBJ_NEXT <= (others => '0');
|
|
OBJ_NB <= (others => '0');
|
|
OBJ_VISINFO_WE <= '0';
|
|
SP1_STEPS <= (others => '0');
|
|
SP1C <= SP1C_Y_RD;
|
|
|
|
when SP1C_Y_RD =>
|
|
if SP1_EN = '1' and DE = '1' then --check one sprite/pixel, this matches the original HW behavior
|
|
OBJ_CACHE_ADDR_RD_SP1 <= OBJ_NEXT;
|
|
SP1C <= SP1C_Y_RD2;
|
|
end if;
|
|
|
|
if SP1_EN = '1' then
|
|
SP1_STEPS <= SP1_STEPS + 1;
|
|
end if;
|
|
if SP1_STEPS = OBJ_MAX_FRAME then
|
|
SP1C <= SP1C_DONE;
|
|
end if;
|
|
|
|
when SP1C_Y_RD2 =>
|
|
SP1C <= SP1C_Y_RD3;
|
|
|
|
when SP1C_Y_RD3 =>
|
|
if LSM = "11" then
|
|
y_offset := "0100000000" + SP1_Y - OBJ_CACHE_Q(9 downto 0);
|
|
OBJ_Y_OFS <= y_offset(9 downto 1);
|
|
else
|
|
y_offset := "0010000000" + SP1_Y - ('0' & OBJ_CACHE_Q(8 downto 0));
|
|
OBJ_Y_OFS <= y_offset(8 downto 0);
|
|
end if;
|
|
OBJ_VS1 <= OBJ_CACHE_Q(25 downto 24);
|
|
OBJ_LINK <= OBJ_CACHE_Q(22 downto 16);
|
|
SP1C <= SP1C_Y_TST;
|
|
|
|
when SP1C_Y_TST =>
|
|
SP1C <= SP1C_NEXT;
|
|
if (OBJ_VS1 = "00" and OBJ_Y_OFS(8 downto 3) = "000000") or -- 8 pix
|
|
(OBJ_VS1 = "01" and OBJ_Y_OFS(8 downto 4) = "00000") or -- 16 pix
|
|
(OBJ_VS1 = "11" and OBJ_Y_OFS(8 downto 5) = "0000") or -- 32 pix
|
|
(OBJ_VS1 = "10" and OBJ_Y_OFS(8 downto 5) = "0000" and OBJ_Y_OFS(4 downto 3) /= "11") --24 pix
|
|
then
|
|
SP1C <= SP1C_SHOW;
|
|
end if;
|
|
|
|
when SP1C_SHOW =>
|
|
-- synthesis translate_off
|
|
write(L, string'("OBJ ID="));
|
|
hwrite(L, "0" & OBJ_NEXT);
|
|
write(L, string'(" Y = "));
|
|
hwrite(L, "000000" & OBJ_CACHE_Q(9 downto 0));
|
|
write(L, string'(" VS = "));
|
|
hwrite(L, "000000" & OBJ_VS1);
|
|
write(L, string'(" LINK = "));
|
|
hwrite(L, "0" & OBJ_LINK);
|
|
write(L, string'(" SP1_Y = "));
|
|
hwrite(L, "0000000" & SP1_Y);
|
|
write(L, string'(" HV_VCNT = "));
|
|
hwrite(L, "0000000" & HV_VCNT);
|
|
write(L, string'(" OFS ="));
|
|
hwrite(L, "000000" & OBJ_Y_OFS);
|
|
write(L, string'(" OBJ_NB ="));
|
|
hwrite(L, "000" & OBJ_NB);
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
OBJ_NB <= OBJ_NB + 1;
|
|
OBJ_VISINFO_WE <= '1';
|
|
OBJ_VISINFO_ADDR_WR <= OBJ_NB;
|
|
OBJ_VISINFO_D <= OBJ_NEXT;
|
|
SP1C <= SP1C_NEXT;
|
|
|
|
when SP1C_NEXT =>
|
|
OBJ_VISINFO_WE <= '0';
|
|
OBJ_TOT <= OBJ_TOT + 1;
|
|
OBJ_NEXT <= OBJ_LINK;
|
|
|
|
-- limit number of sprites per line to 20 / 16
|
|
if OBJ_NB = OBJ_MAX_LINE then
|
|
SP1C <= SP1C_DONE;
|
|
-- check a total of 80 sprites in H40 mode and 64 sprites in H32 mode
|
|
elsif OBJ_TOT = OBJ_MAX_FRAME - 1 or
|
|
-- the following checks are inspired by the gens-ii emulator
|
|
OBJ_LINK >= OBJ_MAX_FRAME or
|
|
OBJ_LINK = "0000000"
|
|
then
|
|
SP1C <= SP1C_DONE;
|
|
else
|
|
SP1C <= SP1C_Y_RD;
|
|
end if;
|
|
|
|
when others => -- SP1C_DONE
|
|
OBJ_VISINFO_WE <= '0';
|
|
OBJ_VISINFO_ADDR_WR <= (others => '0');
|
|
|
|
if SP1E_ACTIVATE = '1' then
|
|
SP1C <= SP1C_INIT;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
----------------------------------------------------------------
|
|
-- SPRITE ENGINE - PART TWO
|
|
----------------------------------------------------------------
|
|
--fetch X and size info for visible sprites
|
|
process( RST_N, CLK )
|
|
variable y_offset: std_logic_vector(9 downto 0);
|
|
begin
|
|
if RST_N = '0' then
|
|
SP2_SEL <= '0';
|
|
SP2C <= SP2C_DONE;
|
|
OBJ_CACHE_ADDR_RD_SP2 <= (others => '0');
|
|
OBJ_SPINFO_ADDR_WR <= (others => '0');
|
|
OBJ_SPINFO_WE <= '0';
|
|
|
|
elsif rising_edge(CLK) then
|
|
|
|
case SP2C is
|
|
when SP2C_INIT =>
|
|
SP2_Y <= PRE_Y; -- Latch the current PRE_Y value
|
|
|
|
-- Treat VISINFO as a shift register, so start reading
|
|
-- from the first unused location.
|
|
-- This way visible sprites processed late.
|
|
if OBJ_NB = OBJ_MAX_LINE
|
|
then
|
|
OBJ_IDX <= (others => '0');
|
|
OBJ_VISINFO_ADDR_RD <= (others => '0');
|
|
else
|
|
OBJ_IDX <= OBJ_NB;
|
|
OBJ_VISINFO_ADDR_RD <= OBJ_NB;
|
|
end if;
|
|
|
|
SP2C <= SP2C_Y_RD;
|
|
|
|
when SP2C_Y_RD =>
|
|
if SP2_EN = '1' then
|
|
if OBJ_IDX < OBJ_NB then
|
|
SP2C <= SP2C_Y_RD2;
|
|
else
|
|
SP2C <= SP2C_NEXT;
|
|
end if;
|
|
end if;
|
|
|
|
when SP2C_Y_RD2 =>
|
|
OBJ_CACHE_ADDR_RD_SP2 <= OBJ_VISINFO_Q(6 downto 0);
|
|
SP2C <= SP2C_Y_RD3;
|
|
when SP2C_Y_RD3 =>
|
|
SP2C <= SP2C_Y_RD4;
|
|
when SP2C_Y_RD4 =>
|
|
if LSM = "11" then
|
|
y_offset := "0100000000" + SP2_Y - OBJ_CACHE_Q(9 downto 0);
|
|
else
|
|
y_offset := "0010000000" + SP2_Y - ('0' & OBJ_CACHE_Q(8 downto 0));
|
|
end if;
|
|
--save only the last 5(6 in doubleres) bits of the offset for part 3
|
|
--Titan 2 textured cube (ab)uses this
|
|
OBJ_SPINFO_D(5 downto 0) <= y_offset(5 downto 0); --Y offset
|
|
OBJ_SPINFO_D(7 downto 6) <= OBJ_CACHE_Q(25 downto 24); --VS
|
|
OBJ_SPINFO_D(9 downto 8) <= OBJ_CACHE_Q(27 downto 26); --HS
|
|
|
|
SP2_VRAM_ADDR <= (SATB(6 downto 0) & "00000000") + (OBJ_VISINFO_Q(6 downto 0) & "10");
|
|
SP2_SEL <= '1';
|
|
|
|
SP2C <= SP2C_RD;
|
|
|
|
when SP2C_RD =>
|
|
if SP2_VRAM32_ACK = '1' then
|
|
SP2_SEL <= '0';
|
|
OBJ_SPINFO_D(34) <= SP2_VRAM32_DO(15); --PRI
|
|
OBJ_SPINFO_D(33 downto 32) <= SP2_VRAM32_DO(14 downto 13); --PAL
|
|
OBJ_SPINFO_D(31) <= SP2_VRAM32_DO(12); --VF
|
|
OBJ_SPINFO_D(30) <= SP2_VRAM32_DO(11); --HF
|
|
OBJ_SPINFO_D(29 downto 19) <= SP2_VRAM32_DO(10 downto 0); --PAT
|
|
OBJ_SPINFO_D(18 downto 10) <= SP2_VRAM32_DO(24 downto 16); --X
|
|
OBJ_SPINFO_ADDR_WR <= OBJ_IDX;
|
|
OBJ_SPINFO_WE <= '1';
|
|
SP2C <= SP2C_NEXT;
|
|
end if;
|
|
|
|
when SP2C_NEXT =>
|
|
OBJ_SPINFO_WE <= '0';
|
|
SP2C <= SP2C_Y_RD;
|
|
if OBJ_IDX = OBJ_MAX_LINE - 1
|
|
then
|
|
if OBJ_NB = 0 or OBJ_NB = OBJ_MAX_LINE
|
|
then
|
|
OBJ_IDX <= OBJ_NB;
|
|
SP2C <= SP2C_DONE;
|
|
else
|
|
OBJ_IDX <= (others => '0');
|
|
OBJ_VISINFO_ADDR_RD <= (others => '0');
|
|
end if;
|
|
else
|
|
if OBJ_NB = OBJ_IDX + 1 then
|
|
OBJ_IDX <= OBJ_NB;
|
|
SP2C <= SP2C_DONE;
|
|
else
|
|
OBJ_IDX <= OBJ_IDX + 1;
|
|
OBJ_VISINFO_ADDR_RD <= OBJ_IDX + 1;
|
|
end if;
|
|
end if;
|
|
|
|
when others => -- SP2C_DONE
|
|
SP2_SEL <= '0';
|
|
|
|
if SP2E_ACTIVATE = '1' then
|
|
SP2C <= SP2C_INIT;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
----------------------------------------------------------------
|
|
-- SPRITE ENGINE - PART THREE
|
|
----------------------------------------------------------------
|
|
process( RST_N, CLK )
|
|
variable obj_vs_var : std_logic_vector(1 downto 0);
|
|
variable obj_hs_var : std_logic_vector(1 downto 0);
|
|
variable obj_hf_var : std_logic;
|
|
variable obj_vf_var : std_logic;
|
|
variable obj_x_var : std_logic_vector(8 downto 0);
|
|
variable obj_y_ofs_var: std_logic_vector(5 downto 0);
|
|
variable obj_pat_var : std_logic_vector(10 downto 0);
|
|
variable obj_color : std_logic_vector(3 downto 0);
|
|
|
|
-- synthesis translate_off
|
|
file F : text open write_mode is "sp3_dbg.out";
|
|
variable L : line;
|
|
-- synthesis translate_on
|
|
begin
|
|
if RST_N = '0' then
|
|
SP3_SEL <= '0';
|
|
SP3C <= SP3C_DONE;
|
|
|
|
OBJ_DOT_OVERFLOW <= '0';
|
|
|
|
SCOL_SET <= '0';
|
|
SOVR_SET <= '0';
|
|
|
|
elsif rising_edge(CLK) then
|
|
|
|
SCOL_SET <= '0';
|
|
SOVR_SET <= '0';
|
|
|
|
case SP3C is
|
|
when SP3C_INIT =>
|
|
OBJ_NO <= (others => '0');
|
|
OBJ_SPINFO_ADDR_RD <= (others => '0');
|
|
OBJ_PIX <= (others => '0');
|
|
OBJ_MASKED <= '0';
|
|
OBJ_VALID_X <= OBJ_DOT_OVERFLOW;
|
|
OBJ_DOT_OVERFLOW <= '0';
|
|
SP3C <= SP3C_NEXT;
|
|
|
|
when SP3C_NEXT =>
|
|
|
|
OBJ_COLINFO_WE_SP3 <= '0';
|
|
|
|
SP3C <= SP3C_LOOP;
|
|
if OBJ_NO = OBJ_IDX then
|
|
SP3C <= SP3C_DONE;
|
|
end if;
|
|
|
|
obj_vs_var := OBJ_SPINFO_Q(7 downto 6);
|
|
OBJ_VS <= obj_vs_var;
|
|
obj_hs_var := OBJ_SPINFO_Q(9 downto 8);
|
|
OBJ_HS <= obj_hs_var;
|
|
obj_x_var := OBJ_SPINFO_Q(18 downto 10);
|
|
if LSM = "11" then
|
|
obj_pat_var := OBJ_SPINFO_Q(28 downto 19) & '0';
|
|
obj_y_ofs_var := OBJ_SPINFO_Q(5 downto 0);
|
|
else
|
|
obj_pat_var := OBJ_SPINFO_Q(29 downto 19);
|
|
obj_y_ofs_var := '0' & OBJ_SPINFO_Q(4 downto 0);
|
|
end if;
|
|
obj_hf_var := OBJ_SPINFO_Q(30);
|
|
OBJ_HF <= obj_hf_var;
|
|
obj_vf_var := OBJ_SPINFO_Q(31);
|
|
OBJ_PAL <= OBJ_SPINFO_Q(33 downto 32);
|
|
OBJ_PRI <= OBJ_SPINFO_Q(34);
|
|
|
|
OBJ_SPINFO_ADDR_RD <= OBJ_NO + 1;
|
|
OBJ_NO <= OBJ_NO + 1;
|
|
|
|
-- sprite masking algorithm as implemented by gens-ii
|
|
if obj_x_var = "000000000" and OBJ_VALID_X = '1' then
|
|
OBJ_MASKED <= '1';
|
|
end if;
|
|
|
|
if obj_x_var /= "000000000" then
|
|
OBJ_VALID_X <= '1';
|
|
end if;
|
|
|
|
OBJ_X_OFS <= "00000";
|
|
if obj_hf_var = '1' then
|
|
case obj_hs_var is
|
|
when "00" => -- 8 pixels
|
|
OBJ_X_OFS <= "00111";
|
|
when "01" => -- 16 pixels
|
|
OBJ_X_OFS <= "01111";
|
|
when "11" => -- 32 pixels
|
|
OBJ_X_OFS <= "11111";
|
|
when others => -- 24 pixels
|
|
OBJ_X_OFS <= "10111";
|
|
end case;
|
|
end if;
|
|
|
|
if LSM = "11" and obj_vf_var = '1' then
|
|
case obj_vs_var is
|
|
when "00" => -- 2*8 pixels
|
|
obj_y_ofs_var := "00" & not(obj_y_ofs_var(3 downto 0));
|
|
when "01" => -- 2*16 pixels
|
|
obj_y_ofs_var := "0" & not(obj_y_ofs_var(4 downto 0));
|
|
when "11" => -- 2*32 pixels
|
|
obj_y_ofs_var := not(obj_y_ofs_var(5 downto 0));
|
|
when others => -- 2*24 pixels
|
|
obj_y_ofs_var := "101111" - obj_y_ofs_var; -- 47-obj_y_ofs
|
|
end case;
|
|
end if;
|
|
|
|
if LSM /= "11" and obj_vf_var = '1' then
|
|
case obj_vs_var is
|
|
when "00" => -- 8 pixels
|
|
obj_y_ofs_var := "000" & not(obj_y_ofs_var(2 downto 0));
|
|
when "01" => -- 16 pixels
|
|
obj_y_ofs_var := "00" & not(obj_y_ofs_var(3 downto 0));
|
|
when "11" => -- 32 pixels
|
|
obj_y_ofs_var := "0" & not(obj_y_ofs_var(4 downto 0));
|
|
when others => -- 24 pixels
|
|
obj_y_ofs_var := "010111" - obj_y_ofs_var(4 downto 0);
|
|
end case;
|
|
end if;
|
|
|
|
OBJ_POS <= obj_x_var - "010000000";
|
|
OBJ_TILEBASE <= (obj_pat_var & "0000") + ("000" & obj_y_ofs_var & "0");
|
|
|
|
-- loop over all tiles of the sprite
|
|
when SP3C_LOOP =>
|
|
OBJ_COLINFO_WE_SP3 <= '0';
|
|
OBJ_COLINFO_ADDR_RD_SP3 <= OBJ_POS;
|
|
|
|
if LSM = "11" then
|
|
case OBJ_VS is
|
|
when "00" => -- 2*8 pixels
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + (OBJ_X_OFS(4 downto 3) & "00000");
|
|
when "01" => -- 2*16 pixels
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + (OBJ_X_OFS(4 downto 3) & "000000");
|
|
when "11" => -- 2*32 pixels
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + (OBJ_X_OFS(4 downto 3) & "0000000");
|
|
when others => -- 2*24 pixels
|
|
case OBJ_X_OFS(4 downto 3) is
|
|
when "00" =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE;
|
|
when "01" =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + "001100000";
|
|
when "11" =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + "100100000";
|
|
when others =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + "011000000";
|
|
end case;
|
|
end case;
|
|
else
|
|
case OBJ_VS is
|
|
when "00" => -- 8 pixels
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + (OBJ_X_OFS(4 downto 3) & "0000");
|
|
when "01" => -- 16 pixels
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + (OBJ_X_OFS(4 downto 3) & "00000");
|
|
when "11" => -- 32 pixels
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + (OBJ_X_OFS(4 downto 3) & "000000");
|
|
when others => -- 24 pixels
|
|
case OBJ_X_OFS(4 downto 3) is
|
|
when "00" =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE;
|
|
when "01" =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + "00110000";
|
|
when "11" =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + "10010000";
|
|
when others =>
|
|
SP3_VRAM_ADDR <= OBJ_TILEBASE + "01100000";
|
|
end case;
|
|
end case;
|
|
end if;
|
|
|
|
SP3_SEL <= '1';
|
|
SP3C <= SP3C_TILE_RD;
|
|
|
|
when SP3C_TILE_RD =>
|
|
if SP3_VRAM32_ACK = '1' then
|
|
SP3_SEL <= '0';
|
|
SP3C <= SP3C_PLOT;
|
|
end if;
|
|
|
|
-- loop over all sprite pixels on the current line
|
|
when SP3C_PLOT =>
|
|
case OBJ_X_OFS(2 downto 0) is
|
|
when "100" =>
|
|
obj_color := SP3_VRAM32_DO(31 downto 28);
|
|
when "101" =>
|
|
obj_color := SP3_VRAM32_DO(27 downto 24);
|
|
when "110" =>
|
|
obj_color := SP3_VRAM32_DO(23 downto 20);
|
|
when "111" =>
|
|
obj_color := SP3_VRAM32_DO(19 downto 16);
|
|
when "000" =>
|
|
obj_color := SP3_VRAM32_DO(15 downto 12);
|
|
when "001" =>
|
|
obj_color := SP3_VRAM32_DO(11 downto 8);
|
|
when "010" =>
|
|
obj_color := SP3_VRAM32_DO( 7 downto 4);
|
|
when "011" =>
|
|
obj_color := SP3_VRAM32_DO( 3 downto 0);
|
|
when others => null;
|
|
end case;
|
|
|
|
OBJ_COLINFO_WE_SP3 <= '0';
|
|
if OBJ_POS < 320 then
|
|
if OBJ_COLINFO_Q_A(3 downto 0) = "0000" then
|
|
if OBJ_MASKED = '0' then
|
|
OBJ_COLINFO_WE_SP3 <= '1';
|
|
OBJ_COLINFO_ADDR_WR_SP3 <= OBJ_POS;
|
|
OBJ_COLINFO_D_SP3 <= OBJ_PRI & OBJ_PAL & obj_color;
|
|
end if;
|
|
else
|
|
if obj_color /= "0000" then
|
|
SCOL_SET <= '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
OBJ_POS <= OBJ_POS + 1;
|
|
OBJ_PIX <= OBJ_PIX + 1;
|
|
OBJ_COLINFO_ADDR_RD_SP3 <= OBJ_POS + 1;
|
|
if OBJ_HF = '1' then
|
|
if OBJ_X_OFS = "00000" then
|
|
SP3C <= SP3C_NEXT;
|
|
else
|
|
OBJ_X_OFS <= OBJ_X_OFS - 1;
|
|
if OBJ_X_OFS(2 downto 0) = "000" then
|
|
SP3C <= SP3C_LOOP; -- fetch the next tile
|
|
else
|
|
SP3C <= SP3C_PLOT;
|
|
end if;
|
|
end if;
|
|
else
|
|
if (OBJ_X_OFS = "00111" and OBJ_HS = "00")
|
|
or (OBJ_X_OFS = "01111" and OBJ_HS = "01")
|
|
or (OBJ_X_OFS = "11111" and OBJ_HS = "11")
|
|
or (OBJ_X_OFS = "10111" and OBJ_HS = "10")
|
|
then
|
|
SP3C <= SP3C_NEXT;
|
|
else
|
|
OBJ_X_OFS <= OBJ_X_OFS + 1;
|
|
if OBJ_X_OFS(2 downto 0) = "111" then
|
|
SP3C <= SP3C_LOOP; -- fetch the next tile
|
|
else
|
|
SP3C <= SP3C_PLOT;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
-- limit total sprite pixels per line
|
|
if (OBJ_PIX = H_DISP_WIDTH AND OBJ_LIMIT_HIGH_EN = '0') OR (OBJ_PIX = H_TOTAL_WIDTH AND OBJ_LIMIT_HIGH_EN = '1') then
|
|
OBJ_DOT_OVERFLOW <= '1';
|
|
SP3C <= SP3C_DONE;
|
|
SOVR_SET <= '1';
|
|
end if;
|
|
|
|
when others => -- SP3C_DONE
|
|
SP3_SEL <= '0';
|
|
|
|
OBJ_COLINFO_WE_SP3 <= '0';
|
|
OBJ_COLINFO_ADDR_WR_SP3 <= (others => '0');
|
|
OBJ_COLINFO_ADDR_RD_SP3 <= (others => '0');
|
|
|
|
OBJ_SPINFO_ADDR_RD <= (others => '0');
|
|
|
|
if SP3E_ACTIVATE = '1' then
|
|
SP3C <= SP3C_INIT;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
----------------------------------------------------------------
|
|
-- VIDEO COUNTING
|
|
----------------------------------------------------------------
|
|
H_DISP_START <= conv_std_logic_vector(H_DISP_START_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(H_DISP_START_H32, 9);
|
|
H_DISP_WIDTH <= conv_std_logic_vector(H_DISP_WIDTH_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(H_DISP_WIDTH_H32, 9);
|
|
H_TOTAL_WIDTH <= conv_std_logic_vector(H_TOTAL_WIDTH_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(H_TOTAL_WIDTH_H32, 9);
|
|
H_INT_POS <= conv_std_logic_vector(H_INT_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(H_INT_H32, 9);
|
|
HSYNC_START <= conv_std_logic_vector(HSYNC_START_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(HSYNC_START_H32, 9);
|
|
HSYNC_END <= conv_std_logic_vector(HSYNC_END_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(HSYNC_END_H32, 9);
|
|
HBLANK_START <= conv_std_logic_vector(HBLANK_START_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(HBLANK_START_H32, 9);
|
|
HBLANK_END <= conv_std_logic_vector(HBLANK_END_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(HBLANK_END_H32, 9);
|
|
HSCROLL_READ <= conv_std_logic_vector(HSCROLL_READ_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(HSCROLL_READ_H32, 9);
|
|
VSYNC_HSTART <= conv_std_logic_vector(VSYNC_HSTART_H40, 9) when H40='1'
|
|
else conv_std_logic_vector(VSYNC_HSTART_H32, 9);
|
|
VSYNC_START <= conv_std_logic_vector(VSYNC_START_PAL_V30, 9) when V30='1' and PAL='1'
|
|
else conv_std_logic_vector(VSYNC_START_PAL_V28, 9) when V30='0' and PAL='1'
|
|
else conv_std_logic_vector(VSYNC_START_NTSC_V30, 9) when V30='1' and PAL='0'
|
|
else conv_std_logic_vector(VSYNC_START_NTSC_V28, 9);
|
|
VBORDER_START <= conv_std_logic_vector(VBORDER_START_PAL_V30, 9) when V30='1' and PAL='1'
|
|
else conv_std_logic_vector(VBORDER_START_PAL_V28, 9) when V30='0' and PAL='1'
|
|
else conv_std_logic_vector(VBORDER_START_NTSC_V30, 9) when V30='1' and PAL='0'
|
|
else conv_std_logic_vector(VBORDER_START_NTSC_V28, 9);
|
|
VBORDER_END <= conv_std_logic_vector(VBORDER_END_PAL_V30, 9) when V30='1' and PAL='1'
|
|
else conv_std_logic_vector(VBORDER_END_PAL_V28, 9) when V30='0' and PAL='1'
|
|
else conv_std_logic_vector(VBORDER_END_NTSC_V30, 9) when V30='1' and PAL='0'
|
|
else conv_std_logic_vector(VBORDER_END_NTSC_V28, 9);
|
|
V_DISP_START <= conv_std_logic_vector(V_DISP_START_V30, 9) when V30='1'
|
|
else conv_std_logic_vector(V_DISP_START_PAL_V28, 9) when PAL='1'
|
|
else conv_std_logic_vector(V_DISP_START_NTSC_V28, 9);
|
|
V_DISP_HEIGHT <= conv_std_logic_vector(V_DISP_HEIGHT_V30, 9) when V30='1'
|
|
else conv_std_logic_vector(V_DISP_HEIGHT_V28, 9);
|
|
V_TOTAL_HEIGHT <= conv_std_logic_vector(PAL_LINES, 9) when PAL='1'
|
|
else conv_std_logic_vector(NTSC_LINES, 9);
|
|
V_INT_POS <= conv_std_logic_vector(V_INT_V30, 9) when V30='1'
|
|
else conv_std_logic_vector(V_INT_V28, 9);
|
|
|
|
-- COUNTERS AND INTERRUPTS
|
|
|
|
Y <= HV_VCNT(7 downto 0);
|
|
BG_Y <= Y & FIELD when LSM = "11" else HV_VCNT;
|
|
PRE_Y <= (Y + 1) & FIELD when LSM = "11" else HV_VCNT + 1;
|
|
|
|
HV_VCNT_EXT <= Y & FIELD_LATCH when LSM = "11" else HV_VCNT;
|
|
HV8 <= HV_VCNT_EXT(8) when LSM = "11" else HV_VCNT_EXT(0);
|
|
|
|
-- refresh slots during disabled display - H40 - 6 slots, H32 - 5 slots
|
|
-- still not sure: usable slots at line -1, border and blanking area
|
|
REFRESH_SLOT <=
|
|
'0' when
|
|
(H40 = '1' and HV_HCNT /= 500 and HV_HCNT /= 52 and HV_HCNT /= 118 and HV_HCNT /= 180 and HV_HCNT /= 244 and HV_HCNT /= 308) or
|
|
(H40 = '0' and HV_HCNT /= 486 and HV_HCNT /= 38 and HV_HCNT /= 102 and HV_HCNT /= 166 and HV_HCNT /= 230) else
|
|
'1';
|
|
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
FIELD <= '0';
|
|
|
|
HV_PIXDIV <= (others => '0');
|
|
HV_HCNT <= (others => '0');
|
|
-- Start the VCounter after VSYNC,
|
|
-- thus various latches can be activated in VDPsim for the 1st frame
|
|
HV_VCNT <= "111100101"; -- 485
|
|
|
|
PRE_V_ACTIVE <= '0';
|
|
V_ACTIVE <= '0';
|
|
V_ACTIVE_DISP <= '0';
|
|
|
|
HINT_EN <= '0';
|
|
HINT_PENDING_SET <= '0';
|
|
VINT_TG68_PENDING_SET <= '0';
|
|
VINT_T80_SET <= '0';
|
|
VINT_T80_CLR <= '0';
|
|
|
|
M_HBL <= '0';
|
|
IN_HBL <= '0';
|
|
IN_VBL <= '1';
|
|
VBL_AREA <= '1';
|
|
|
|
FIFO_EN <= '0';
|
|
SLOT_EN <= '0';
|
|
REFRESH_EN <= '0';
|
|
|
|
SP1_EN <= '0';
|
|
SP2_EN <= '0';
|
|
|
|
elsif rising_edge(CLK) then
|
|
|
|
if M3='0' then
|
|
HV <= HV_VCNT_EXT(7 downto 1) & HV8 & HV_HCNT(8 downto 1);
|
|
end if;
|
|
|
|
HINT_PENDING_SET <= '0';
|
|
VINT_TG68_PENDING_SET <= '0';
|
|
VINT_T80_SET <= '0';
|
|
VINT_T80_CLR <= '0';
|
|
FIFO_EN <= '0';
|
|
SLOT_EN <= '0';
|
|
REFRESH_EN <= '0';
|
|
|
|
SP1_EN <= '0';
|
|
SP2_EN <= '0';
|
|
BGA_MAPPING_EN <= '0';
|
|
BGA_PATTERN_EN <= '0';
|
|
BGB_MAPPING_EN <= '0';
|
|
BGB_PATTERN_EN <= '0';
|
|
|
|
-- H40 slow slots: 8aaaaaaa99aaaaaaa8aaaaaaa99aaaaaaa
|
|
-- 8, 10, 10, 10, 10, 10, 10, 10, 9, 9, 10, 10, 10, 10, 10, 10, 10, 8, 10, 10, 10, 10, 10, 10, 10, 9, 9, 10, 10, 10, 10, 10, 10, 10
|
|
-- 460 468 477 485 493
|
|
|
|
HV_PIXDIV <= HV_PIXDIV + 1;
|
|
if (RS0 = '1' and H40 = '1' and
|
|
((HV_PIXDIV = 8-1 and (HV_HCNT <= 460 or HV_HCNT > 493 or HV_HCNT = 477)) or
|
|
((HV_PIXDIV = 9-1 and (HV_HCNT = 468 or HV_HCNT = 469 or HV_HCNT = 485 or HV_HCNT = 486))) or
|
|
(HV_PIXDIV = 10-1))) or --normal H40 - 28*10+4*9+388*8=3420 cycles
|
|
(RS0 = '0' and H40 = '1' and HV_PIXDIV = 8-1) or --fast H40
|
|
(RS0 = '0' and H40 = '0' and HV_PIXDIV = 10-1) or --normal H32
|
|
(RS0 = '1' and H40 = '0' and HV_PIXDIV = 8-1) then --fast H32
|
|
HV_PIXDIV <= (others => '0');
|
|
if HV_HCNT = H_DISP_START + H_TOTAL_WIDTH - 1 then
|
|
-- counter reset, originally HSYNC begins here
|
|
HV_HCNT <= H_DISP_START;
|
|
else
|
|
HV_HCNT <= HV_HCNT + 1;
|
|
end if;
|
|
|
|
if HV_HCNT = H_INT_POS then
|
|
if HV_VCNT = V_DISP_START + V_TOTAL_HEIGHT - 1 then --VDISP_START is negative
|
|
--just after VSYNC
|
|
HV_VCNT <= V_DISP_START;
|
|
else
|
|
HV_VCNT <= HV_VCNT + 1;
|
|
end if;
|
|
|
|
if HV_VCNT = "1"&x"FF" then
|
|
-- FIELD changes at VINT, but the HV_COUNTER reflects the current field from line 0-0
|
|
FIELD_LATCH <= FIELD;
|
|
end if;
|
|
|
|
-- HINT_EN effect is delayed by one line
|
|
if HV_VCNT = "1"&x"FE" then
|
|
HINT_EN <= '1';
|
|
elsif HV_VCNT = V_DISP_HEIGHT - 1 then
|
|
HINT_EN <= '0';
|
|
end if;
|
|
|
|
if HINT_EN = '0'
|
|
then HINT_COUNT <= HIT;
|
|
else
|
|
if HINT_COUNT = 0 then
|
|
HINT_PENDING_SET <= '1';
|
|
HINT_COUNT <= HIT;
|
|
else
|
|
HINT_COUNT <= HINT_COUNT - 1;
|
|
end if;
|
|
end if;
|
|
|
|
if HV_VCNT = "1"&x"FE" then
|
|
PRE_V_ACTIVE <= '1';
|
|
elsif HV_VCNT = "1"&x"FF" then
|
|
V_ACTIVE <= '1';
|
|
elsif HV_VCNT = V_DISP_HEIGHT - 2 then
|
|
PRE_V_ACTIVE <= '0';
|
|
elsif HV_VCNT = V_DISP_HEIGHT - 1 then
|
|
V_ACTIVE <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
if HV_HCNT = HBLANK_START then
|
|
if HV_VCNT = 0 then
|
|
V_ACTIVE_DISP <= '1';
|
|
elsif HV_VCNT = V_DISP_HEIGHT then
|
|
V_ACTIVE_DISP <= '0';
|
|
end if;
|
|
|
|
if HV_VCNT = VBORDER_START then
|
|
VBL_AREA <= '0';
|
|
end if;
|
|
if HV_VCNT = VBORDER_END then
|
|
VBL_AREA <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
if HV_HCNT = H_INT_POS + 4 then
|
|
if HV_VCNT = "1"&x"FF" then
|
|
IN_VBL <= '0';
|
|
elsif HV_VCNT = V_DISP_HEIGHT then
|
|
IN_VBL <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
if HV_HCNT = HBLANK_END then --active display
|
|
IN_HBL <= '0';
|
|
M_HBL <= '0';
|
|
end if;
|
|
|
|
if HV_HCNT = HBLANK_START then -- blanking
|
|
IN_HBL <= '1';
|
|
end if;
|
|
|
|
if HV_HCNT = HBLANK_START-3 then
|
|
M_HBL <= '1';
|
|
end if;
|
|
|
|
if HV_HCNT = 0 then
|
|
if HV_VCNT = V_INT_POS
|
|
then
|
|
FIELD <= not FIELD;
|
|
VINT_TG68_PENDING_SET <= '1';
|
|
VINT_T80_SET <= '1';
|
|
elsif HV_VCNT = V_INT_POS + 1
|
|
then
|
|
VINT_T80_CLR <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
-- VRAM Access slot enables
|
|
|
|
if IN_VBL = '1' or DE = '0'
|
|
then
|
|
if REFRESH_SLOT = '0' -- skip refresh slots
|
|
then
|
|
FIFO_EN <= not HV_HCNT(0);
|
|
end if;
|
|
else
|
|
if (HV_HCNT(3 downto 0) = "0100" and HV_HCNT(5 downto 4) /= "11" and HV_HCNT < H_DISP_WIDTH) or
|
|
(H40 = '1' and (HV_HCNT = 322 or HV_HCNT = 324 or HV_HCNT = 464)) or
|
|
(H40 = '0' and (HV_HCNT = 290 or HV_HCNT = 486 or HV_HCNT = 258 or HV_HCNT = 260))
|
|
then
|
|
FIFO_EN <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
SP1_EN <= '1'; --SP1 Engine checks one sprite/pixel
|
|
|
|
case HV_HCNT(3 downto 0) is
|
|
when "0010" => BGA_MAPPING_EN <= '1';
|
|
when "0100" => null; -- external or refresh
|
|
when "0110" => BGA_PATTERN_EN <= '1';
|
|
when "1000" => BGA_PATTERN_EN <= '1';
|
|
when "1010" => BGB_MAPPING_EN <= '1';
|
|
when "1100" => SP2_EN <= '1';
|
|
when "1110" => BGB_PATTERN_EN <= '1';
|
|
when "0000" =>
|
|
BGB_PATTERN_EN <= '1';
|
|
if OBJ_LIMIT_HIGH_EN = '1' then
|
|
SP2_EN <= '1'; -- Update SP2 twice as often when sprite limit is increased
|
|
end if;
|
|
when others => null;
|
|
end case;
|
|
|
|
SLOT_EN <= not HV_HCNT(0);
|
|
if (IN_VBL = '1' or DE = '0') and REFRESH_SLOT = '1' then
|
|
REFRESH_EN <= '1';
|
|
end if;
|
|
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- TIMING MANAGEMENT
|
|
-- Background generation runs during active display.
|
|
-- It starts with reading the horizontal scroll values from the VRAM
|
|
BGEN_ACTIVATE <= '1' when V_ACTIVE = '1' and HV_HCNT = HSCROLL_READ + 8 else '0';
|
|
|
|
-- Stage 1 - runs after the vcounter incremented
|
|
-- Carefully choosing the starting position avoids the
|
|
-- "Your emulator suxx" in Titan I demo
|
|
SP1E_ACTIVATE <= '1' when PRE_V_ACTIVE = '1' and HV_HCNT = H_INT_POS + 1 else '0';
|
|
-- Stage 2 - runs in the active area
|
|
SP2E_ACTIVATE <= '1' when PRE_V_ACTIVE = '1' and HV_HCNT = 0 else '0';
|
|
-- Stage 3 runs 3 slots after the background rendering ends
|
|
SP3E_ACTIVATE <= '1' when V_ACTIVE = '1' and HV_HCNT = H_DISP_WIDTH + 5 else '0';
|
|
|
|
process( CLK )
|
|
variable x : std_logic_vector(8 downto 0);
|
|
begin
|
|
OBJ_COLINFO_D_REND <= (others => '0');
|
|
if rising_edge(CLK) then
|
|
|
|
if VBL_AREA = '0' then
|
|
-- As displaying and sprite rendering (part 3) overlap,
|
|
-- copy and clear the sprite buffer a bit sooner.
|
|
-- also apply DE for the sprite layer here and
|
|
-- clear the colinfo buffer after rendering
|
|
--
|
|
-- A smaller buffer would be enough for the second copy, but
|
|
-- it still uses only 1 BRAM block, and makes the logic simpler
|
|
--
|
|
case HV_PIXDIV is
|
|
when "0000" =>
|
|
x := HV_HCNT;
|
|
OBJ_COLINFO_ADDR_RD_REND <= x;
|
|
OBJ_COLINFO_ADDR_WR_REND <= x;
|
|
OBJ_COLINFO2_ADDR_WR <= x;
|
|
OBJ_COLINFO_WE_REND <= '0';
|
|
when "0010" =>
|
|
OBJ_COLINFO2_WE <= '1';
|
|
if DE = '1' then
|
|
OBJ_COLINFO2_D <= OBJ_COLINFO_Q_A;
|
|
else
|
|
OBJ_COLINFO2_D <= '0' & BGCOL;
|
|
end if;
|
|
OBJ_COLINFO_WE_REND <= '1';
|
|
|
|
when "0011" =>
|
|
OBJ_COLINFO2_WE <= '0';
|
|
OBJ_COLINFO_WE_REND <= '0';
|
|
when others => null;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- PIXEL COUNTER AND OUTPUT
|
|
process( RST_N, CLK )
|
|
variable col : std_logic_vector(5 downto 0);
|
|
variable cold: std_logic_vector(5 downto 0);
|
|
variable x : std_logic_vector(8 downto 0);
|
|
begin
|
|
if rising_edge(CLK) then
|
|
|
|
if IN_HBL = '1' or VBL_AREA = '1' then
|
|
BGB_COLINFO_ADDR_B <= (others => '0');
|
|
BGA_COLINFO_ADDR_B <= (others => '0');
|
|
if HV_PIXDIV = "0101" then
|
|
FF_R <= (others => '0');
|
|
FF_G <= (others => '0');
|
|
FF_B <= (others => '0');
|
|
end if;
|
|
else
|
|
case HV_PIXDIV is
|
|
when "0000" =>
|
|
x := HV_HCNT - HBLANK_END - HBORDER_LEFT;
|
|
BGB_COLINFO_ADDR_B <= x;
|
|
BGA_COLINFO_ADDR_B <= x;
|
|
OBJ_COLINFO2_ADDR_RD <= x;
|
|
|
|
when "0010" =>
|
|
if SHI = '1' and BGA_COLINFO_Q_B(6) = '0' and BGB_COLINFO_Q_B(6) = '0' then
|
|
--if all layers are normal priority, then shadowed
|
|
PIX_MODE <= PIX_SHADOW;
|
|
else
|
|
PIX_MODE <= PIX_NORMAL;
|
|
end if;
|
|
|
|
when "0011" =>
|
|
if SHI = '1' and (OBJ_COLINFO2_Q(6) = '1' or
|
|
((BGA_COLINFO_Q_B(6) = '0' or BGA_COLINFO_Q_B(3 downto 0) = "0000") and
|
|
(BGB_COLINFO_Q_B(6) = '0' or BGB_COLINFO_Q_B(3 downto 0) = "0000"))) then
|
|
--sprite is visible
|
|
if OBJ_COLINFO2_Q(5 downto 0) = "111110" then
|
|
--if sprite is palette 3/color 14 increase intensity
|
|
if PIX_MODE = PIX_SHADOW then
|
|
PIX_MODE <= PIX_NORMAL;
|
|
else
|
|
PIX_MODE <= PIX_HIGHLIGHT;
|
|
end if;
|
|
elsif OBJ_COLINFO2_Q(5 downto 0) = "111111" then
|
|
-- if sprite is visible and palette 3/color 15, decrease intensity
|
|
PIX_MODE <= PIX_SHADOW;
|
|
elsif (OBJ_COLINFO2_Q(6) = '1' and OBJ_COLINFO2_Q(3 downto 0) /= "0000") or
|
|
OBJ_COLINFO2_Q(3 downto 0) = "1110" then
|
|
--sprite color 14 or high prio always shows up normal
|
|
PIX_MODE <= PIX_NORMAL;
|
|
end if;
|
|
end if;
|
|
|
|
if OBJ_COLINFO2_Q(3 downto 0) /= "0000" and OBJ_COLINFO2_Q(6) = '1' and
|
|
(SHI='0' or OBJ_COLINFO2_Q(5 downto 1) /= "11111") then
|
|
col := OBJ_COLINFO2_Q(5 downto 0);
|
|
elsif BGA_COLINFO_Q_B(3 downto 0) /= "0000" and BGA_COLINFO_Q_B(6) = '1' then
|
|
col := BGA_COLINFO_Q_B(5 downto 0);
|
|
elsif BGB_COLINFO_Q_B(3 downto 0) /= "0000" and BGB_COLINFO_Q_B(6) = '1' then
|
|
col := BGB_COLINFO_Q_B(5 downto 0);
|
|
elsif OBJ_COLINFO2_Q(3 downto 0) /= "0000" and
|
|
(SHI='0' or OBJ_COLINFO2_Q(5 downto 1) /= "11111") then
|
|
col := OBJ_COLINFO2_Q(5 downto 0);
|
|
elsif BGA_COLINFO_Q_B(3 downto 0) /= "0000" then
|
|
col := BGA_COLINFO_Q_B(5 downto 0);
|
|
elsif BGB_COLINFO_Q_B(3 downto 0) /= "0000" then
|
|
col := BGB_COLINFO_Q_B(5 downto 0);
|
|
else
|
|
col := BGCOL;
|
|
end if;
|
|
|
|
case DBG(8 downto 7) is
|
|
when "00" => cold := BGCOL;
|
|
when "01" => cold := OBJ_COLINFO2_Q(5 downto 0);
|
|
when "10" => cold := BGA_COLINFO_Q_B(5 downto 0);
|
|
when "11" => cold := BGB_COLINFO_Q_B(5 downto 0);
|
|
when others => null;
|
|
end case;
|
|
|
|
if DBG(6) = '1' then
|
|
col := cold;
|
|
elsif DBG(8 downto 7) /= "00" then
|
|
col := col and cold;
|
|
end if;
|
|
|
|
if x >= H_DISP_WIDTH or V_ACTIVE_DISP = '0' then
|
|
-- border area
|
|
col := BGCOL;
|
|
PIX_MODE <= PIX_NORMAL;
|
|
end if;
|
|
|
|
CRAM_ADDR_B <= col;
|
|
|
|
when "0101" =>
|
|
if (x >= H_DISP_WIDTH or V_ACTIVE_DISP = '0') and (BORDER_EN = '0' or DBG(8 downto 7) /= "00") then
|
|
-- disabled border
|
|
FF_B <= (others => '0');
|
|
FF_G <= (others => '0');
|
|
FF_R <= (others => '0');
|
|
else case PIX_MODE is
|
|
when PIX_SHADOW =>
|
|
-- half brightness
|
|
FF_B <= '0' & CRAM_Q_B(8 downto 6);
|
|
FF_G <= '0' & CRAM_Q_B(5 downto 3);
|
|
FF_R <= '0' & CRAM_Q_B(2 downto 0);
|
|
|
|
when PIX_NORMAL =>
|
|
-- normal brightness
|
|
FF_B <= CRAM_Q_B(8 downto 6) & '0';
|
|
FF_G <= CRAM_Q_B(5 downto 3) & '0';
|
|
FF_R <= CRAM_Q_B(2 downto 0) & '0';
|
|
|
|
when PIX_HIGHLIGHT =>
|
|
-- increased brightness
|
|
FF_B <= '0' & CRAM_Q_B(8 downto 6) + 7;
|
|
FF_G <= '0' & CRAM_Q_B(5 downto 3) + 7;
|
|
FF_R <= '0' & CRAM_Q_B(2 downto 0) + 7;
|
|
end case;
|
|
end if;
|
|
|
|
when others => null;
|
|
end case;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
end process;
|
|
|
|
----------------------------------------------------------------
|
|
-- VIDEO OUTPUT
|
|
----------------------------------------------------------------
|
|
-- SYNC
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
FF_VS <= '1';
|
|
FF_HS <= '1';
|
|
elsif rising_edge(CLK) then
|
|
|
|
-- horizontal sync
|
|
if HV_HCNT = HSYNC_START then
|
|
FF_HS <= '0';
|
|
elsif HV_HCNT = HSYNC_END then
|
|
FF_HS <= '1';
|
|
end if;
|
|
|
|
if HV_HCNT = VSYNC_HSTART then
|
|
if HV_VCNT = VSYNC_START then
|
|
FF_VS <= '0';
|
|
end if;
|
|
if HV_VCNT = VSYNC_START + VS_LINES - 1 then
|
|
FF_VS <= '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- VSync extension by half a line for interlace
|
|
process( CLK )
|
|
-- 1710 = 1/2 * 3420 clock per line
|
|
variable VS_START_DELAY : integer range 0 to 1710;
|
|
variable VS_END_DELAY : integer range 0 to 1710;
|
|
variable VS_DELAY_ACTIVE: boolean;
|
|
begin
|
|
if rising_edge( CLK ) then
|
|
if FF_VS = '1' then
|
|
-- LSM(0) = 1 and FIELD = 0 right before vsync start -> start the delay
|
|
if HV_HCNT = VSYNC_HSTART and HV_VCNT = VSYNC_START and LSM(0) = '1' and FIELD = '0' then
|
|
VS_START_DELAY := 1710;
|
|
VS_DELAY_ACTIVE := true;
|
|
end if;
|
|
|
|
-- FF_VS already inactive, but end delay still != 0
|
|
if VS_END_DELAY /= 0 then
|
|
VS_END_DELAY := VS_END_DELAY - 1;
|
|
else
|
|
VS <= '1';
|
|
end if;
|
|
|
|
else
|
|
-- FF_VS = '0'
|
|
if VS_DELAY_ACTIVE then
|
|
VS_END_DELAY := 1710;
|
|
VS_DELAY_ACTIVE := false;
|
|
end if;
|
|
|
|
-- FF_VS active, but start delay still != 0
|
|
if VS_START_DELAY /= 0 then
|
|
VS_START_DELAY := VS_START_DELAY - 1;
|
|
else
|
|
VS <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- VS <= FF_VS;
|
|
HS <= FF_HS;
|
|
|
|
R <= FF_R;
|
|
G <= FF_G;
|
|
B <= FF_B;
|
|
|
|
INTERLACE <= LSM(1) and LSM(0);
|
|
RESOLUTION <= V30&H40;
|
|
|
|
V_DISP_HEIGHT_R <= conv_std_logic_vector(V_DISP_HEIGHT_V30, 9) when V30_R ='1'
|
|
else conv_std_logic_vector(V_DISP_HEIGHT_V28, 9);
|
|
|
|
process( CLK )
|
|
variable V30prev : std_logic;
|
|
begin
|
|
if rising_edge(CLK) then
|
|
CE_PIX <= '0';
|
|
if HV_PIXDIV = "0101" then
|
|
|
|
if HV_HCNT = VSYNC_HSTART and HV_VCNT = VSYNC_START then
|
|
FIELD_OUT <= LSM(1) and LSM(0) and not FIELD_LATCH;
|
|
end if;
|
|
|
|
V30prev := V30prev and V30;
|
|
if HV_HCNT = H_INT_POS and HV_VCNT = 0 then
|
|
V30_R <= V30prev;
|
|
V30prev := '1';
|
|
end if;
|
|
|
|
CE_PIX <= '1';
|
|
if BORDER_EN = '0' then
|
|
if ((HV_HCNT - HBLANK_END - HBORDER_LEFT) >= H_DISP_WIDTH) then
|
|
HBL <= '1';
|
|
else
|
|
HBL <= '0';
|
|
end if;
|
|
|
|
if HV_VCNT < V_DISP_HEIGHT_R then
|
|
VBL <= '0';
|
|
else
|
|
VBL <= '1';
|
|
end if;
|
|
else
|
|
HBL <= M_HBL;
|
|
VBL <= VBL_AREA;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
----------------------------------------------------------------
|
|
-- VIDEO DEBUG
|
|
----------------------------------------------------------------
|
|
-- synthesis translate_off
|
|
process( CE_PIX )
|
|
file F : text open write_mode is "vdp.out";
|
|
variable L : line;
|
|
begin
|
|
if rising_edge( CE_PIX ) then
|
|
hwrite(L, FF_R & '0' & FF_G & '0' & FF_B & '0');
|
|
writeline(F,L);
|
|
end if;
|
|
end process;
|
|
-- synthesis translate_on
|
|
|
|
----------------------------------------------------------------
|
|
-- CPU INTERFACE & DATA TRANSFER CONTROLLER
|
|
----------------------------------------------------------------
|
|
DTACK_N <= FF_DTACK_N;
|
|
DO <= FF_DO;
|
|
|
|
VBUS_ADDR <= FF_VBUS_ADDR;
|
|
VBUS_SEL <= FF_VBUS_SEL;
|
|
|
|
FIFO_EMPTY <= '1' when FIFO_QUEUE = 0 and FIFO_PARTIAL = '0' else '0';
|
|
FIFO_FULL <= '1' when (FIFO_QUEUE(2) = '1') or (FIFO_QUEUE = 3 and FIFO_PARTIAL = '1') else '0';
|
|
|
|
process( RST_N, CLK )
|
|
-- synthesis translate_off
|
|
file F : text open write_mode is "vdp_dbg.out";
|
|
variable L : line;
|
|
-- synthesis translate_on
|
|
begin
|
|
if RST_N = '0' then
|
|
|
|
FF_DTACK_N <= '1';
|
|
FF_DO <= (others => '1');
|
|
|
|
PENDING <= '0';
|
|
CODE <= (others => '0');
|
|
|
|
DT_RD_SEL <= '0';
|
|
DT_RD_DTACK_N <= '1';
|
|
|
|
SOVR_CLR <= '0';
|
|
SCOL_CLR <= '0';
|
|
|
|
DBG <= (others => '0');
|
|
|
|
REG <= (others => (others => '0'));
|
|
|
|
ADDR <= (others => '0');
|
|
|
|
DT_VRAM_SEL <= '0';
|
|
|
|
FIFO_RD_POS <= "00";
|
|
FIFO_WR_POS <= "00";
|
|
FIFO_QUEUE <= "000";
|
|
FIFO_PARTIAL <= '0';
|
|
|
|
REFRESH_FLAG <= '0';
|
|
|
|
FF_VBUS_ADDR <= (others => '0');
|
|
FF_VBUS_SEL <= '0';
|
|
|
|
DMA_FILL <= '0';
|
|
DMAF_SET_REQ <= '0';
|
|
DMA_COPY <= '0';
|
|
DMA_VBUS <= '0';
|
|
DMA_SOURCE <= (others => '0');
|
|
DMA_LENGTH <= (others => '0');
|
|
|
|
DTC <= DTC_IDLE;
|
|
DMAC <= DMA_IDLE;
|
|
|
|
BR_N <= '1';
|
|
BGACK_N_REG <= '1';
|
|
|
|
elsif rising_edge(CLK) then
|
|
|
|
if DT_RD_SEL = '0' then
|
|
DT_RD_DTACK_N <= '1';
|
|
end if;
|
|
|
|
if SLOT_EN = '1' then
|
|
if FIFO_DELAY(0) /= "00" then FIFO_DELAY(0) <= FIFO_DELAY(0) - 1; end if;
|
|
if FIFO_DELAY(1) /= "00" then FIFO_DELAY(1) <= FIFO_DELAY(1) - 1; end if;
|
|
if FIFO_DELAY(2) /= "00" then FIFO_DELAY(2) <= FIFO_DELAY(2) - 1; end if;
|
|
if FIFO_DELAY(3) /= "00" then FIFO_DELAY(3) <= FIFO_DELAY(3) - 1; end if;
|
|
end if;
|
|
|
|
CRAM_WE_A <= '0';
|
|
|
|
SOVR_CLR <= '0';
|
|
SCOL_CLR <= '0';
|
|
|
|
if SEL = '0' then
|
|
FF_DTACK_N <= '1';
|
|
elsif SEL = '1' and FF_DTACK_N = '1' then
|
|
if RNW = '0' then -- Write
|
|
if A(4 downto 2) = "000" then
|
|
-- Data Port
|
|
PENDING <= '0';
|
|
|
|
if FIFO_FULL = '0' and DTC /= DTC_FIFO_RD and FF_DTACK_N = '1' then
|
|
FIFO_ADDR( CONV_INTEGER( FIFO_WR_POS ) ) <= ADDR;
|
|
FIFO_DATA( CONV_INTEGER( FIFO_WR_POS ) ) <= DI;
|
|
FIFO_CODE( CONV_INTEGER( FIFO_WR_POS ) ) <= CODE(3 downto 0);
|
|
FIFO_DELAY( CONV_INTEGER( FIFO_WR_POS ) ) <= "10";
|
|
FIFO_WR_POS <= FIFO_WR_POS + 1;
|
|
FIFO_QUEUE <= FIFO_QUEUE + 1;
|
|
ADDR <= ADDR + ADDR_STEP;
|
|
FF_DTACK_N <= '0';
|
|
end if;
|
|
|
|
elsif A(4 downto 2) = "001" then
|
|
-- Control Port
|
|
if PENDING = '1' then
|
|
CODE(4 downto 2) <= DI(6 downto 4);
|
|
ADDR <= DI(2 downto 0) & ADDR(13 downto 0);
|
|
|
|
if DMA = '1' then
|
|
CODE(5) <= DI(7);
|
|
if DI(7) = '1' then
|
|
if REG(23)(7) = '0' then
|
|
DMA_VBUS <= '1';
|
|
BR_N <= '0';
|
|
else
|
|
if REG(23)(6) = '0' then
|
|
DMA_FILL <= '1';
|
|
else
|
|
DMA_COPY <= '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
FF_DTACK_N <= '0';
|
|
PENDING <= '0';
|
|
else
|
|
CODE(1 downto 0) <= DI(15 downto 14);
|
|
if DI(15 downto 14) = "10" then
|
|
-- Register Set
|
|
if (M5 = '1' or DI(12 downto 8) <= 10) then
|
|
-- mask registers above 10 in Mode4
|
|
REG( CONV_INTEGER( DI(12 downto 8)) ) <= DI(7 downto 0);
|
|
end if;
|
|
FF_DTACK_N <= '0';
|
|
else
|
|
-- Address Set
|
|
ADDR(13 downto 0) <= DI(13 downto 0);
|
|
FF_DTACK_N <= '0';
|
|
PENDING <= '1';
|
|
CODE(5 downto 4) <= "00"; -- attempt to fix lotus i
|
|
end if;
|
|
-- Note : Genesis Plus does address setting
|
|
-- even in Register Set mode. Normal ?
|
|
end if;
|
|
elsif A(4 downto 2) = "111" then
|
|
DBG <= DI;
|
|
FF_DTACK_N <= '0';
|
|
elsif A(4 downto 3) = "10" then
|
|
-- PSG
|
|
FF_DTACK_N <= '0';
|
|
else
|
|
-- Unused (Lock-up)
|
|
FF_DTACK_N <= '0';
|
|
end if;
|
|
else -- Read
|
|
if A(4 downto 2) = "000" then
|
|
PENDING <= '0';
|
|
-- Data Port
|
|
if CODE = "001000" -- CRAM Read
|
|
or CODE = "000100" -- VSRAM Read
|
|
or CODE = "000000" -- VRAM Read
|
|
or CODE = "001100" -- VRAM Read 8 bit
|
|
then
|
|
if DT_RD_DTACK_N = '1' then
|
|
DT_RD_SEL <= '1';
|
|
DT_RD_CODE <= CODE(3 downto 0);
|
|
else
|
|
DT_RD_SEL <= '0';
|
|
FF_DO <= DT_RD_DATA;
|
|
FF_DTACK_N <= '0';
|
|
end if;
|
|
else
|
|
FF_DTACK_N <= '0';
|
|
end if;
|
|
elsif A(4 downto 2) = "001" then
|
|
-- Control Port (Read Status Register)
|
|
PENDING <= '0';
|
|
FF_DO <= STATUS;
|
|
SOVR_CLR <= '1';
|
|
SCOL_CLR <= '1';
|
|
FF_DTACK_N <= '0';
|
|
elsif A(4 downto 3) = "01" then
|
|
-- HV Counter
|
|
FF_DO <= HV;
|
|
FF_DTACK_N <= '0';
|
|
elsif A(4) = '1' then
|
|
-- unused, PSG, DBG
|
|
FF_DO <= x"FFFF";
|
|
FF_DTACK_N <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
if SLOT_EN = '1' then
|
|
if REFRESH_EN = '1' and DMA_VBUS = '1' and CODE(3 downto 0) /= "0001" then
|
|
-- skip the slot after a refresh for DMA (except for VRAM write)
|
|
REFRESH_FLAG <= '1';
|
|
else
|
|
REFRESH_FLAG <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
case DTC is
|
|
when DTC_IDLE =>
|
|
if FIFO_EN = '1' then
|
|
FIFO_PARTIAL <= '0';
|
|
end if;
|
|
|
|
if VRAM_SPEED = '0' or (FIFO_EN = '1' and FIFO_PARTIAL = '0' and REFRESH_FLAG = '0') then
|
|
if FIFO_EMPTY = '0' and FIFO_DELAY( CONV_INTEGER( FIFO_RD_POS ) ) = 0 then
|
|
DTC <= DTC_FIFO_RD;
|
|
elsif DT_RD_SEL = '1' and DT_RD_DTACK_N = '1' then
|
|
case DT_RD_CODE is
|
|
when "1000" => -- CRAM Read
|
|
DTC <= DTC_CRAM_RD;
|
|
when "0100" => -- VSRAM Read
|
|
DTC <= DTC_VSRAM_RD;
|
|
when others => -- VRAM Read
|
|
DTC <= DTC_VRAM_RD1;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
|
|
when DTC_FIFO_RD =>
|
|
DT_WR_ADDR <= FIFO_ADDR( CONV_INTEGER( FIFO_RD_POS ) );
|
|
DT_WR_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) );
|
|
FIFO_RD_POS <= FIFO_RD_POS + 1;
|
|
FIFO_QUEUE <= FIFO_QUEUE - 1;
|
|
case FIFO_CODE( CONV_INTEGER( FIFO_RD_POS ) ) is
|
|
when "0011" => -- CRAM Write
|
|
DTC <= DTC_CRAM_WR;
|
|
when "0101" => -- VSRAM Write
|
|
DTC <= DTC_VSRAM_WR;
|
|
when "0001" => -- VRAM Write
|
|
if M128 = '0' then
|
|
--skip next FIFO slot since we write 16 bit now instead of the original 8
|
|
FIFO_PARTIAL <= '1';
|
|
end if;
|
|
DTC <= DTC_VRAM_WR1;
|
|
when others => --invalid target
|
|
DTC <= DTC_WR_END;
|
|
end case;
|
|
|
|
when DTC_VRAM_WR1 =>
|
|
-- synthesis translate_off
|
|
write(L, string'(" VRAM WR ["));
|
|
hwrite(L, x"00" & DT_WR_ADDR(15 downto 1) & '0');
|
|
write(L, string'("] = ["));
|
|
if DT_WR_ADDR(0) = '0' then
|
|
hwrite(L, DT_WR_DATA);
|
|
else
|
|
hwrite(L, DT_WR_DATA(7 downto 0) & DT_WR_DATA(15 downto 8));
|
|
end if;
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
DT_VRAM_SEL <= not DT_VRAM_SEL;
|
|
DT_VRAM_RNW <= '0';
|
|
DT_VRAM_ADDR <= DT_WR_ADDR(16 downto 1);
|
|
DT_VRAM_UDS_N <= '0';
|
|
DT_VRAM_LDS_N <= '0';
|
|
if DT_WR_ADDR(0) = '0' or M128 = '1' then
|
|
DT_VRAM_DI <= DT_WR_DATA;
|
|
else
|
|
DT_VRAM_DI <= DT_WR_DATA(7 downto 0) & DT_WR_DATA(15 downto 8);
|
|
end if;
|
|
|
|
DTC <= DTC_VRAM_WR2;
|
|
|
|
when DTC_VRAM_WR2 =>
|
|
if early_ack_dt='0' then
|
|
DTC <= DTC_WR_END;
|
|
end if;
|
|
|
|
when DTC_CRAM_WR =>
|
|
-- synthesis translate_off
|
|
write(L, string'(" CRAM WR ["));
|
|
hwrite(L, x"00" & DT_WR_ADDR(15 downto 1) & '0');
|
|
write(L, string'("] = ["));
|
|
hwrite(L, DT_WR_DATA);
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
CRAM_WE_A <= '1';
|
|
CRAM_ADDR_A <= DT_WR_ADDR(6 downto 1);
|
|
CRAM_D_A <= DT_WR_DATA(11 downto 9) & DT_WR_DATA(7 downto 5) & DT_WR_DATA(3 downto 1);
|
|
DTC <= DTC_WR_END;
|
|
|
|
when DTC_VSRAM_WR =>
|
|
-- synthesis translate_off
|
|
write(L, string'(" VSRAM WR ["));
|
|
hwrite(L, x"00" & DT_WR_ADDR(15 downto 1) & '0');
|
|
write(L, string'("] = ["));
|
|
hwrite(L, DT_WR_DATA);
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
if DT_WR_ADDR(6 downto 1) < 40 then
|
|
if DT_WR_ADDR(1) = '0' then
|
|
VSRAM0_WE_A <= '1';
|
|
VSRAM0_ADDR_A <= DT_WR_ADDR(6 downto 2);
|
|
VSRAM0_D_A <= DT_WR_DATA(10 downto 0);
|
|
else
|
|
VSRAM1_WE_A <= '1';
|
|
VSRAM1_ADDR_A <= DT_WR_ADDR(6 downto 2);
|
|
VSRAM1_D_A <= DT_WR_DATA(10 downto 0);
|
|
end if;
|
|
end if;
|
|
DTC <= DTC_WR_END;
|
|
|
|
when DTC_WR_END =>
|
|
VSRAM0_WE_A <= '0';
|
|
VSRAM1_WE_A <= '0';
|
|
if DMA_FILL = '1' then
|
|
DMAF_SET_REQ <= '1';
|
|
end if;
|
|
DTC <= DTC_IDLE;
|
|
|
|
when DTC_VRAM_RD1 =>
|
|
DT_VRAM_SEL <= not DT_VRAM_SEL;
|
|
DT_VRAM_ADDR <= '0'&ADDR(15 downto 1);
|
|
DT_VRAM_RNW <= '1';
|
|
DT_VRAM_UDS_N <= '0';
|
|
DT_VRAM_LDS_N <= '0';
|
|
DTC <= DTC_VRAM_RD2;
|
|
|
|
when DTC_VRAM_RD2 =>
|
|
if early_ack_dt='0' then
|
|
if DT_RD_CODE = "1100" then
|
|
-- VRAM 8 bit read - unused bits come from the next FIFO entry
|
|
if ADDR(0) = '0' then
|
|
DT_RD_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(15 downto 8) & DT_VRAM_DO(7 downto 0);
|
|
else
|
|
DT_RD_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(15 downto 8) & DT_VRAM_DO(15 downto 8);
|
|
end if;
|
|
else
|
|
DT_RD_DATA <= DT_VRAM_DO;
|
|
end if;
|
|
DT_RD_DTACK_N <= '0';
|
|
ADDR <= ADDR + ADDR_STEP;
|
|
DTC <= DTC_IDLE;
|
|
end if;
|
|
|
|
when DTC_CRAM_RD =>
|
|
CRAM_ADDR_A <= ADDR(6 downto 1);
|
|
DTC <= DTC_CRAM_RD1;
|
|
|
|
when DTC_CRAM_RD1 =>
|
|
-- cram address is set up
|
|
DTC <= DTC_CRAM_RD2;
|
|
|
|
when DTC_CRAM_RD2 =>
|
|
DT_RD_DATA(11 downto 9) <= CRAM_Q_A(8 downto 6);
|
|
DT_RD_DATA(7 downto 5) <= CRAM_Q_A(5 downto 3);
|
|
DT_RD_DATA(3 downto 1) <= CRAM_Q_A(2 downto 0);
|
|
--unused bits come from the next FIFO entry
|
|
DT_RD_DATA(15 downto 12) <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(15 downto 12);
|
|
DT_RD_DATA(8) <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(8);
|
|
DT_RD_DATA(4) <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(4);
|
|
DT_RD_DATA(0) <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(0);
|
|
DT_RD_DTACK_N <= '0';
|
|
ADDR <= ADDR + ADDR_STEP;
|
|
DTC <= DTC_IDLE;
|
|
|
|
when DTC_VSRAM_RD =>
|
|
VSRAM0_ADDR_A <= ADDR(6 downto 2);
|
|
VSRAM1_ADDR_A <= ADDR(6 downto 2);
|
|
DTC <= DTC_VSRAM_RD2;
|
|
|
|
when DTC_VSRAM_RD2 =>
|
|
DTC <= DTC_VSRAM_RD3;
|
|
|
|
when DTC_VSRAM_RD3 =>
|
|
if ADDR(6 downto 1) < 40 then
|
|
if ADDR(1) = '0' then
|
|
DT_RD_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(15 downto 11) & VSRAM0_Q_A;
|
|
else
|
|
DT_RD_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(15 downto 11) & VSRAM1_Q_A;
|
|
end if;
|
|
elsif ADDR(1) = '0' then
|
|
DT_RD_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(15 downto 11) & BGA_VSRAM0_LATCH;
|
|
else
|
|
DT_RD_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_RD_POS ) )(15 downto 11) & BGB_VSRAM1_LATCH;
|
|
end if;
|
|
DT_RD_DTACK_N <= '0';
|
|
ADDR <= ADDR + ADDR_STEP;
|
|
DTC <= DTC_IDLE;
|
|
|
|
when others => null;
|
|
end case;
|
|
|
|
----------------------------------------------------------------
|
|
-- DMA ENGINE
|
|
----------------------------------------------------------------
|
|
if FIFO_EMPTY = '1' and DMA_FILL = '1' and DMAF_SET_REQ = '1' then
|
|
if CODE(3 downto 0) = "0011" or CODE(3 downto 0) = "0101" then
|
|
-- CRAM, VSRAM fill gets its data from the next FIFO write position
|
|
DT_DMAF_DATA <= FIFO_DATA( CONV_INTEGER( FIFO_WR_POS ) );
|
|
else -- VRAM Write
|
|
DT_DMAF_DATA <= DT_WR_DATA;
|
|
end if;
|
|
DMAF_SET_REQ <= '0';
|
|
end if;
|
|
|
|
case DMAC is
|
|
when DMA_IDLE =>
|
|
if DMA_VBUS = '1' then
|
|
DMAC <= DMA_VBUS_INIT;
|
|
elsif DMA_FILL = '1' and DMAF_SET_REQ = '1' then
|
|
DMAC <= DMA_FILL_INIT;
|
|
elsif DMA_COPY = '1' then
|
|
DMAC <= DMA_COPY_INIT;
|
|
end if;
|
|
----------------------------------------------------------------
|
|
-- DMA FILL
|
|
----------------------------------------------------------------
|
|
|
|
when DMA_FILL_INIT =>
|
|
-- synthesis translate_off
|
|
write(L, string'("VDP DMA FILL SRC=["));
|
|
hwrite(L, x"00" & ADDR);
|
|
write(L, string'("] LEN=["));
|
|
hwrite(L, x"00" & REG(20) & REG(19));
|
|
write(L, string'("] VALUE=["));
|
|
hwrite(L, DT_DMAF_DATA(7 downto 0));
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
DMA_SOURCE <= REG(22) & REG(21);
|
|
DMA_LENGTH <= REG(20) & REG(19);
|
|
DMAC <= DMA_FILL_START;
|
|
|
|
when DMA_FILL_START =>
|
|
if FIFO_EMPTY = '1' and DTC = DTC_IDLE and DMAF_SET_REQ = '0' then
|
|
-- suspend FILL if the FIFO is not empty
|
|
case CODE(3 downto 0) is
|
|
when "0011" => -- CRAM Write
|
|
DMAC <= DMA_FILL_CRAM;
|
|
when "0101" => -- VSRAM Write
|
|
DMAC <= DMA_FILL_VSRAM;
|
|
when "0001" => -- VRAM Write
|
|
DMAC <= DMA_FILL_WR;
|
|
when others => -- invalid target
|
|
DMAC <= DMA_FILL_NEXT;
|
|
end case;
|
|
end if;
|
|
|
|
when DMA_FILL_CRAM =>
|
|
if VRAM_SPEED = '0' or FIFO_EN = '1' then
|
|
CRAM_WE_A <= '1';
|
|
CRAM_ADDR_A <= ADDR(6 downto 1);
|
|
CRAM_D_A <= DT_DMAF_DATA(11 downto 9) & DT_DMAF_DATA(7 downto 5) & DT_DMAF_DATA(3 downto 1);
|
|
DMAC <= DMA_FILL_NEXT;
|
|
end if;
|
|
|
|
when DMA_FILL_VSRAM =>
|
|
if VRAM_SPEED = '0' or FIFO_EN = '1' then
|
|
if ADDR(6 downto 1) < 40 then
|
|
if ADDR(1) = '0' then
|
|
VSRAM0_WE_A <= '1';
|
|
VSRAM0_ADDR_A <= ADDR(6 downto 2);
|
|
VSRAM0_D_A <= DT_DMAF_DATA(10 downto 0);
|
|
else
|
|
VSRAM1_WE_A <= '1';
|
|
VSRAM1_ADDR_A <= ADDR(6 downto 2);
|
|
VSRAM1_D_A <= DT_DMAF_DATA(10 downto 0);
|
|
end if;
|
|
end if;
|
|
DMAC <= DMA_FILL_NEXT;
|
|
end if;
|
|
|
|
when DMA_FILL_WR =>
|
|
if VRAM_SPEED = '0' or FIFO_EN = '1' then
|
|
-- synthesis translate_off
|
|
write(L, string'(" VRAM WR ["));
|
|
hwrite(L, x"00" & ADDR(15 downto 1) & '0');
|
|
write(L, string'("] = ["));
|
|
if ADDR(0) = '0' then
|
|
write(L, string'(" "));
|
|
hwrite(L, DT_DMAF_DATA(7 downto 0));
|
|
else
|
|
hwrite(L, DT_DMAF_DATA(7 downto 0));
|
|
write(L, string'(" "));
|
|
end if;
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
DT_VRAM_SEL <= not DT_VRAM_SEL;
|
|
DT_VRAM_ADDR <= '0'&ADDR(15 downto 1);
|
|
DT_VRAM_RNW <= '0';
|
|
DT_VRAM_DI <= DT_DMAF_DATA(15 downto 8) & DT_DMAF_DATA(15 downto 8);
|
|
if ADDR(0) = '0' then
|
|
DT_VRAM_UDS_N <= '1';
|
|
DT_VRAM_LDS_N <= '0';
|
|
else
|
|
DT_VRAM_UDS_N <= '0';
|
|
DT_VRAM_LDS_N <= '1';
|
|
end if;
|
|
DMAC <= DMA_FILL_WR2;
|
|
end if;
|
|
|
|
when DMA_FILL_WR2 =>
|
|
if early_ack_dt='0' then
|
|
DMAC <= DMA_FILL_NEXT;
|
|
end if;
|
|
|
|
when DMA_FILL_NEXT =>
|
|
VSRAM0_WE_A <= '0';
|
|
VSRAM1_WE_A <= '0';
|
|
ADDR <= ADDR + ADDR_STEP;
|
|
DMA_SOURCE <= DMA_SOURCE + ADDR_STEP;
|
|
DMA_LENGTH <= DMA_LENGTH - 1;
|
|
DMAC <= DMA_FILL_LOOP;
|
|
|
|
when DMA_FILL_LOOP =>
|
|
REG(20) <= DMA_LENGTH(15 downto 8);
|
|
REG(19) <= DMA_LENGTH(7 downto 0);
|
|
REG(22) <= DMA_SOURCE(15 downto 8);
|
|
REG(21) <= DMA_SOURCE(7 downto 0);
|
|
if DMA_LENGTH = 0 then
|
|
DMA_FILL <= '0';
|
|
DMAC <= DMA_IDLE;
|
|
-- synthesis translate_off
|
|
write(L, string'("VDP DMA FILL END"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
else
|
|
DMAC <= DMA_FILL_START;
|
|
end if;
|
|
|
|
----------------------------------------------------------------
|
|
-- DMA COPY
|
|
----------------------------------------------------------------
|
|
|
|
when DMA_COPY_INIT =>
|
|
-- synthesis translate_off
|
|
write(L, string'("VDP DMA COPY SRC=["));
|
|
hwrite(L, x"00" & REG(22) & REG(21));
|
|
write(L, string'("] DST=["));
|
|
hwrite(L, x"00" & ADDR);
|
|
write(L, string'("] LEN=["));
|
|
hwrite(L, x"00" & REG(20) & REG(19));
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
DMA_LENGTH <= REG(20) & REG(19);
|
|
DMA_SOURCE <= REG(22) & REG(21);
|
|
DMAC <= DMA_COPY_RD;
|
|
|
|
when DMA_COPY_RD =>
|
|
DT_VRAM_SEL <= not DT_VRAM_SEL;
|
|
DT_VRAM_ADDR <= '0'&DMA_SOURCE(15 downto 1);
|
|
DT_VRAM_RNW <= '1';
|
|
DT_VRAM_UDS_N <= '0';
|
|
DT_VRAM_LDS_N <= '0';
|
|
DMAC <= DMA_COPY_RD2;
|
|
|
|
when DMA_COPY_RD2 =>
|
|
if early_ack_dt='0' then
|
|
-- synthesis translate_off
|
|
write(L, string'(" VRAM RD ["));
|
|
hwrite(L, x"00" & DMA_SOURCE(15 downto 1) & '0');
|
|
write(L, string'("] = ["));
|
|
if DMA_SOURCE(0) = '0' then
|
|
write(L, string'(" "));
|
|
hwrite(L, DT_VRAM_DO(15 downto 8));
|
|
else
|
|
hwrite(L, DT_VRAM_DO(7 downto 0));
|
|
write(L, string'(" "));
|
|
end if;
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
DMAC <= DMA_COPY_WR;
|
|
end if;
|
|
|
|
when DMA_COPY_WR =>
|
|
-- synthesis translate_off
|
|
write(L, string'(" VRAM WR ["));
|
|
hwrite(L, x"00" & ADDR(15 downto 1) & '0');
|
|
write(L, string'("] = ["));
|
|
if ADDR(0) = '0' then
|
|
write(L, string'(" "));
|
|
hwrite(L, DT_VRAM_DI(15 downto 8));
|
|
else
|
|
hwrite(L, DT_VRAM_DI(7 downto 0));
|
|
write(L, string'(" "));
|
|
end if;
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
DT_VRAM_SEL <= not DT_VRAM_SEL;
|
|
DT_VRAM_ADDR <= '0'&ADDR(15 downto 1);
|
|
DT_VRAM_RNW <= '0';
|
|
if DMA_SOURCE(0) = '0' then
|
|
DT_VRAM_DI <= DT_VRAM_DO(7 downto 0) & DT_VRAM_DO(7 downto 0);
|
|
else
|
|
DT_VRAM_DI <= DT_VRAM_DO(15 downto 8) & DT_VRAM_DO(15 downto 8);
|
|
end if;
|
|
if ADDR(0) = '0' then
|
|
DT_VRAM_UDS_N <= '1';
|
|
DT_VRAM_LDS_N <= '0';
|
|
else
|
|
DT_VRAM_UDS_N <= '0';
|
|
DT_VRAM_LDS_N <= '1';
|
|
end if;
|
|
DMAC <= DMA_COPY_WR2;
|
|
|
|
when DMA_COPY_WR2 =>
|
|
if early_ack_dt='0' then
|
|
ADDR <= ADDR + ADDR_STEP;
|
|
DMA_LENGTH <= DMA_LENGTH - 1;
|
|
DMA_SOURCE <= DMA_SOURCE + 1;
|
|
DMAC <= DMA_COPY_LOOP;
|
|
end if;
|
|
|
|
when DMA_COPY_LOOP =>
|
|
REG(20) <= DMA_LENGTH(15 downto 8);
|
|
REG(19) <= DMA_LENGTH(7 downto 0);
|
|
REG(22) <= DMA_SOURCE(15 downto 8);
|
|
REG(21) <= DMA_SOURCE(7 downto 0);
|
|
if DMA_LENGTH = 0 then
|
|
DMA_COPY <= '0';
|
|
DMAC <= DMA_IDLE;
|
|
-- synthesis translate_off
|
|
write(L, string'("VDP DMA COPY END"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
else
|
|
DMAC <= DMA_COPY_RD;
|
|
end if;
|
|
|
|
----------------------------------------------------------------
|
|
-- DMA VBUS
|
|
----------------------------------------------------------------
|
|
|
|
when DMA_VBUS_INIT =>
|
|
-- synthesis translate_off
|
|
write(L, string'("VDP DMA VBUS SRC=["));
|
|
hwrite(L, REG(23)(6 downto 0) & REG(22) & REG(21) & '0');
|
|
write(L, string'("] DST=["));
|
|
hwrite(L, x"00" & ADDR);
|
|
write(L, string'("] LEN=["));
|
|
hwrite(L, x"00" & REG(20) & REG(19));
|
|
write(L, string'("]"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
DMA_LENGTH <= REG(20) & REG(19);
|
|
DMA_SOURCE <= REG(22) & REG(21);
|
|
DMA_VBUS_TIMER <= "10";
|
|
DMAC <= DMA_VBUS_WAIT;
|
|
|
|
when DMA_VBUS_WAIT =>
|
|
if BG_N = '0' then
|
|
BGACK_N_REG <= '0';
|
|
BR_N <= '1';
|
|
end if;
|
|
if SLOT_EN = '1' then
|
|
if DMA_VBUS_TIMER = 0 then
|
|
if BGACK_N_REG = '0' then
|
|
DMAC <= DMA_VBUS_RD;
|
|
FF_VBUS_SEL <= '1';
|
|
FF_VBUS_ADDR <= REG(23)(6 downto 0) & DMA_SOURCE;
|
|
end if;
|
|
else
|
|
DMA_VBUS_TIMER <= DMA_VBUS_TIMER - 1;
|
|
end if;
|
|
end if;
|
|
|
|
when DMA_VBUS_RD =>
|
|
if VBUS_DTACK_N = '0' or FF_VBUS_SEL = '0' then
|
|
FF_VBUS_SEL <= '0';
|
|
if FF_VBUS_SEL = '1' then
|
|
DT_DMAV_DATA <= VBUS_DATA;
|
|
end if;
|
|
if FIFO_FULL = '0' and DTC /= DTC_FIFO_RD then
|
|
FIFO_ADDR( CONV_INTEGER( FIFO_WR_POS ) ) <= ADDR;
|
|
if FF_VBUS_SEL = '1' then
|
|
FIFO_DATA( CONV_INTEGER( FIFO_WR_POS ) ) <= VBUS_DATA;
|
|
else
|
|
FIFO_DATA( CONV_INTEGER( FIFO_WR_POS ) ) <= DT_DMAV_DATA;
|
|
end if;
|
|
FIFO_CODE( CONV_INTEGER( FIFO_WR_POS ) ) <= CODE(3 downto 0);
|
|
FIFO_DELAY( CONV_INTEGER( FIFO_WR_POS ) ) <= "10";
|
|
FIFO_WR_POS <= FIFO_WR_POS + 1;
|
|
FIFO_QUEUE <= FIFO_QUEUE + 1;
|
|
ADDR <= ADDR + ADDR_STEP;
|
|
|
|
DMA_LENGTH <= DMA_LENGTH - 1;
|
|
DMA_SOURCE <= DMA_SOURCE + 1;
|
|
DMAC <= DMA_VBUS_LOOP;
|
|
end if;
|
|
end if;
|
|
|
|
when DMA_VBUS_LOOP =>
|
|
REG(20) <= DMA_LENGTH(15 downto 8);
|
|
REG(19) <= DMA_LENGTH(7 downto 0);
|
|
REG(22) <= DMA_SOURCE(15 downto 8);
|
|
REG(21) <= DMA_SOURCE(7 downto 0);
|
|
if DMA_LENGTH = 0 then
|
|
DMA_VBUS_TIMER <= "01";
|
|
DMAC <= DMA_VBUS_END;
|
|
-- synthesis translate_off
|
|
write(L, string'("VDP DMA VBUS END"));
|
|
writeline(F,L);
|
|
-- synthesis translate_on
|
|
elsif SLOT_EN = '1' then
|
|
FF_VBUS_SEL <= '1';
|
|
FF_VBUS_ADDR <= REG(23)(6 downto 0) & DMA_SOURCE;
|
|
DMAC <= DMA_VBUS_RD;
|
|
end if;
|
|
|
|
when DMA_VBUS_END =>
|
|
if SLOT_EN = '1' then
|
|
DMA_VBUS_TIMER <= DMA_VBUS_TIMER - 1;
|
|
if DMA_VBUS_TIMER = 0 then
|
|
DMA_VBUS <= '0';
|
|
BGACK_N_REG <= '1';
|
|
DMAC <= DMA_IDLE;
|
|
end if;
|
|
end if;
|
|
when others => null;
|
|
end case;
|
|
end if;
|
|
|
|
end process;
|
|
|
|
----------------------------------------------------------------
|
|
-- INTERRUPTS AND VARIOUS LATCHES
|
|
----------------------------------------------------------------
|
|
|
|
-- HINT PENDING
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
HINT_PENDING <= '0';
|
|
VINT_TG68_PENDING <= '0';
|
|
elsif rising_edge( CLK) then
|
|
INTACK_D <= INTACK;
|
|
--acknowledge interrupts serially
|
|
if INTACK_D = '0' and INTACK = '1' then
|
|
if VINT_TG68_FF = '1' then
|
|
VINT_TG68_PENDING <= '0';
|
|
elsif HINT_FF = '1' then
|
|
HINT_PENDING <= '0';
|
|
end if;
|
|
end if;
|
|
if HINT_PENDING_SET = '1' then
|
|
HINT_PENDING <= '1';
|
|
end if;
|
|
if VINT_TG68_PENDING_SET = '1' then
|
|
VINT_TG68_PENDING <= '1';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- HINT
|
|
HINT <= HINT_FF;
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
HINT_FF <= '0';
|
|
elsif rising_edge( CLK) then
|
|
if HINT_PENDING = '1' and IE1 = '1' then
|
|
HINT_FF <= '1';
|
|
else
|
|
HINT_FF <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- VINT - TG68
|
|
VINT_TG68 <= VINT_TG68_FF;
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
VINT_TG68_FF <= '0';
|
|
elsif rising_edge( CLK) then
|
|
if VINT_TG68_PENDING = '1' and IE0 = '1' then
|
|
VINT_TG68_FF <= '1';
|
|
else
|
|
VINT_TG68_FF <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- VINT - T80
|
|
VINT_T80 <= VINT_T80_FF;
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
VINT_T80_FF <= '0';
|
|
elsif rising_edge( CLK) then
|
|
if VINT_T80_SET = '1' then
|
|
VINT_T80_FF <= '1';
|
|
elsif VINT_T80_CLR = '1' then
|
|
VINT_T80_FF <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Sprite Collision
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
SCOL <= '0';
|
|
elsif rising_edge( CLK) then
|
|
if SCOL_SET = '1' then
|
|
SCOL <= '1';
|
|
elsif SCOL_CLR = '1' then
|
|
SCOL <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Sprite Overflow
|
|
process( RST_N, CLK )
|
|
begin
|
|
if RST_N = '0' then
|
|
SOVR <= '0';
|
|
elsif rising_edge( CLK) then
|
|
if SOVR_SET = '1' then
|
|
SOVR <= '1';
|
|
elsif SOVR_CLR = '1' then
|
|
SOVR <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end rtl;
|
|
|