📄 video_vicii_656x_a.vhd
字号:
-- -----------------------------------------------------------------------
--
-- FPGA 64
--
-- A fully functional commodore 64 implementation in a single FPGA
--
-- -----------------------------------------------------------------------
-- Peter Wendrich (pwsoft@syntiac.com)
-- http://www.syntiac.com/fpga64.html
-- -----------------------------------------------------------------------
--
-- VIC-II - Video Interface Chip no 2
--
-- -----------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
-- -----------------------------------------------------------------------
architecture rtl of video_vicii_656x is
type vicCycles is (
cycleRefresh1, cycleRefresh2, cycleRefresh3, cycleRefresh4, cycleRefresh5,
cycleIdle1,
cycleChar,
cycleCalcSprites, cycleSpriteBa1, cycleSpriteBa2, cycleSpriteBa3,
cycleSpriteA, cycleSpriteB
);
subtype ColorDef is unsigned(3 downto 0);
type MFlags is array(0 to 7) of boolean;
type MXdef is array(0 to 7) of unsigned(8 downto 0);
type MYdef is array(0 to 7) of unsigned(7 downto 0);
type MCntDef is array(0 to 7) of unsigned(5 downto 0);
type MPixelsDef is array(0 to 7) of unsigned(23 downto 0);
type MCurrentPixelDef is array(0 to 7) of unsigned(1 downto 0);
type charStoreDef is array(38 downto 0) of unsigned(11 downto 0);
type spriteColorsDef is array(7 downto 0) of unsigned(3 downto 0);
type pixelColorStoreDef is array(7 downto 0) of unsigned(3 downto 0);
-- State machine
signal lastLineFlag : boolean; -- True for on last line of the frame.
signal beyondFrameFlag : boolean; -- Y>frame lines
signal vicCycle : vicCycles := cycleRefresh1;
signal sprite : unsigned(2 downto 0) := "000";
signal shiftChars : boolean;
signal idle: std_logic := '1';
signal rasterIrqDone : std_logic; -- Only one interrupt each rasterLine
signal rasterEnable: std_logic;
-- BA signal
signal badLine : boolean; -- true if we have a badline condition
signal baLoc : std_logic;
signal baCnt : unsigned(2 downto 0);
signal baChars : std_logic;
signal baSprite04 : std_logic;
signal baSprite15 : std_logic;
signal baSprite26 : std_logic;
signal baSprite37 : std_logic;
-- Memory refresh cycles
signal refreshCounter : unsigned(7 downto 0);
-- User registers
signal MX : MXdef; -- Sprite X
signal MY : MYdef; -- Sprite Y
signal ME : unsigned(7 downto 0); -- Sprite enable
signal MXE : unsigned(7 downto 0); -- Sprite X expansion
signal MYE : unsigned(7 downto 0); -- Sprite Y expansion
signal MPRIO : unsigned(7 downto 0); -- Sprite priority
signal MC : unsigned(7 downto 0); -- sprite multi color
-- !!! Krestage 3 hacks
signal MCDelay : unsigned(7 downto 0); -- sprite multi color
-- mode
signal BMM: std_logic; -- Bitmap mode
signal ECM: std_logic; -- Extended color mode
signal MCM: std_logic; -- Multi color mode
signal DEN: std_logic; -- DMA enable
signal RSEL: std_logic; -- Visible rows selection (24/25)
signal CSEL: std_logic; -- Visible columns selection (38/40)
signal RES: std_logic;
signal VM: unsigned(13 downto 10);
signal CB: unsigned(13 downto 11);
signal EC : ColorDef; -- border color
signal B0C : ColorDef; -- background color 0
signal B1C : ColorDef; -- background color 1
signal B2C : ColorDef; -- background color 2
signal B3C : ColorDef; -- background color 3
signal MM0 : ColorDef; -- sprite multicolor 0
signal MM1 : ColorDef; -- sprite multicolor 1
signal spriteColors: spriteColorsDef;
-- borders and blanking
signal LRBorder: std_logic;
signal TBBorder: std_logic;
signal hBlack: std_logic;
signal vBlanking : std_logic;
signal hBlanking : std_logic;
signal xscroll: unsigned(2 downto 0);
signal yscroll: unsigned(2 downto 0);
signal rasterCmp : unsigned(8 downto 0);
-- Address generator
signal vicAddrReg : unsigned(13 downto 0);
signal vicAddrLoc : unsigned(13 downto 0);
-- Address counters
signal ColCounter: unsigned(9 downto 0) := (others => '0');
signal ColRestart: unsigned(9 downto 0) := (others => '0');
signal RowCounter: unsigned(2 downto 0) := (others => '0');
-- IRQ Registers
signal IRST: std_logic := '0';
signal ERST: std_logic := '0';
signal IMBC: std_logic := '0';
signal EMBC: std_logic := '0';
signal IMMC: std_logic := '0';
signal EMMC: std_logic := '0';
signal ILP: std_logic := '0';
signal ELP: std_logic := '0';
signal IRQ: std_logic;
-- Collision detection registers
signal M2M: unsigned(7 downto 0); -- Sprite to sprite collision
signal M2D: unsigned(7 downto 0); -- Sprite to character collision
signal M2Mhit : std_logic;
signal M2Dhit : std_logic;
-- Raster counters
signal rasterX : unsigned(9 downto 0) := (others => '0');
signal rasterY : unsigned(8 downto 0) := (others => '0');
-- Light pen
signal lightPenHit: std_logic;
signal lpX : unsigned(7 downto 0);
signal lpY : unsigned(7 downto 0);
-- IRQ Resets
signal resetLightPenIrq: std_logic;
signal resetIMMC : std_logic;
signal resetIMBC : std_logic;
signal resetRasterIrq : std_logic;
-- Character generation
signal charStore: charStoreDef;
signal nextChar : unsigned(11 downto 0);
-- Char/Pixels just coming from memory
signal readChar : unsigned(11 downto 0);
signal readPixels : unsigned(7 downto 0);
-- Char/Pixels pair waiting to be shifted
signal waitingChar : unsigned(11 downto 0);
signal waitingPixels : unsigned(7 downto 0);
-- Stores colorinfo and the Pixels that are currently in shift register
signal shiftingChar : unsigned(11 downto 0);
signal shiftingPixels : unsigned(7 downto 0);
signal shifting_ff : std_logic; -- Multicolor shift-regiter status bit.
-- Sprite work registers
signal MPtr : unsigned(7 downto 0); -- sprite base pointer
signal MPixels : MPixelsDef; -- Sprite 24 bit shift register
signal MActive : MFlags; -- Sprite is active (derived from MCnt)
signal MCnt : MCntDef;
signal MXE_ff : unsigned(7 downto 0); -- Sprite X expansion flipflop
signal MYE_ff : unsigned(7 downto 0); -- Sprite Y expansion flipflop
signal MC_ff : unsigned(7 downto 0); -- controls sprite shift-register in multicolor
signal MShift : MFlags; -- Sprite is shifting
signal MCurrentPixel : MCurrentPixelDef;
-- Current colors and pixels
signal pixelColor: ColorDef;
signal pixelBgFlag: std_logic; -- For collision detection
signal pixelDelay: pixelColorStoreDef;
-- Read/Write lines
signal myWr : std_logic;
signal myRd : std_logic;
begin
-- -----------------------------------------------------------------------
-- Ouput signals
-- -----------------------------------------------------------------------
ba <= baLoc;
vicAddr <= vicAddrReg when registeredAddress else vicAddrLoc;
hSync <= hBlanking;
vSync <= vBlanking;
irq_n <= not IRQ;
-- -----------------------------------------------------------------------
-- chip-select signals
-- -----------------------------------------------------------------------
myWr <= cs and we;
myRd <= cs and rd;
-- -----------------------------------------------------------------------
-- debug signals
-- -----------------------------------------------------------------------
debugX <= rasterX;
debugY <= rasterY;
-- -----------------------------------------------------------------------
-- Badline condition
-- -----------------------------------------------------------------------
process(rasterY, yscroll, rasterEnable)
begin
badLine <= false;
if (rasterY(2 downto 0) = yscroll)
and (rasterEnable = '1') then
badLine <= true;
end if;
end process;
-- -----------------------------------------------------------------------
-- BA=low counter
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if baLoc = '0' then
if phi = '0'
and enaData = '1'
and baCnt(2) = '0' then
baCnt <= baCnt + 1;
end if;
else
baCnt <= (others => '0');
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Calculate lastLineFlag
-- -----------------------------------------------------------------------
process(clk)
variable rasterLines : integer range 0 to 312;
begin
if rising_edge(clk) then
lastLineFlag <= false;
rasterLines := 311; -- PAL
if mode6567old = '1' then
rasterLines := 261; -- NTSC (R7 and earlier have 262 lines)
end if;
if mode6567R8 = '1' then
rasterLines := 262; -- NTSC (R8 and newer have 263 lines)
end if;
if rasterY = rasterLines then
lastLineFlag <= true;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- State machine
-- -----------------------------------------------------------------------
vicStateMachine: process(clk)
begin
if rising_edge(clk) then
if enaData = '1'
and baSync = '0' then
if phi = '0' then
case vicCycle is
when cycleRefresh1 =>
vicCycle <= cycleRefresh2;
if ((mode6567old or mode6567R8) = '1') then
vicCycle <= cycleIdle1;
end if;
when cycleIdle1 => vicCycle <= cycleRefresh2;
when cycleRefresh2 => vicCycle <= cycleRefresh3;
when cycleRefresh3 => vicCycle <= cycleRefresh4;
when cycleRefresh4 => vicCycle <= cycleRefresh5; -- X=0..7 on this cycle
when cycleRefresh5 => vicCycle <= cycleChar;
when cycleChar =>
if ((mode6569 = '1') and rasterX(9 downto 3) = "0100111") -- PAL
or ((mode6567old = '1') and rasterX(9 downto 3) = "0100111") -- Old NTSC
or ((mode6567R8 = '1') and rasterX(9 downto 3) = "0101000") -- New NTSC
or ((mode6572 = '1') and rasterX(9 downto 3) = "0101000") then -- PAL-N
vicCycle <= cycleCalcSprites;
end if;
when cycleCalcSprites => vicCycle <= cycleSpriteBa1;
when cycleSpriteBa1 => vicCycle <= cycleSpriteBa2;
when cycleSpriteBa2 => vicCycle <= cycleSpriteBa3;
when others =>
null;
end case;
else
case vicCycle is
when cycleSpriteBa3 => vicCycle <= cycleSpriteA;
when cycleSpriteA =>
vicCycle <= cycleSpriteB;
when cycleSpriteB =>
vicCycle <= cycleSpriteA;
if sprite = 7 then
vicCycle <= cycleRefresh1;
end if;
when others =>
null;
end case;
end if;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Iterate through all sprites.
-- Only used when state-machine above is in any sprite cycles.
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if phi = '1'
and enaData = '1'
and vicCycle = cycleSpriteB
and baSync = '0' then
sprite <= sprite + 1;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Address generator
-- -----------------------------------------------------------------------
process(phi, vicCycle, sprite, shiftChars, idle,
VM, CB, ECM, BMM, nextChar, colCounter, rowCounter, MPtr, MCnt)
begin
--
-- Default case ($3FFF fetches)
vicAddrLoc <= (others => '1');
if (idle = '0')
and shiftChars then
if BMM = '1' then
vicAddrLoc <= CB(13) & colCounter & rowCounter;
else
vicAddrLoc <= CB & nextChar(7 downto 0) & rowCounter;
end if;
end if;
if ECM = '1' then
vicAddrLoc(10 downto 9) <= "00";
end if;
case vicCycle is
when cycleRefresh1 | cycleRefresh2 | cycleRefresh3 | cycleRefresh4 | cycleRefresh5 =>
if emulateRefresh then
vicAddrLoc <= "111111" & refreshCounter;
else
vicAddrLoc <= (others => '-');
end if;
when cycleSpriteBa1 | cycleSpriteBa2 | cycleSpriteBa3 =>
vicAddrLoc <= (others => '1');
when cycleSpriteA =>
vicAddrLoc <= VM & "1111111" & sprite;
if phi = '1' then
vicAddrLoc <= MPtr & MCnt(to_integer(sprite));
end if;
when cycleSpriteB =>
vicAddrLoc <= MPtr & MCnt(to_integer(sprite));
when others =>
if phi = '1' then
vicAddrLoc <= VM & colCounter;
end if;
end case;
end process;
-- Registered address
process(clk)
begin
if rising_edge(clk) then
vicAddrReg <= vicAddrLoc;
end if;
end process;
-- -----------------------------------------------------------------------
-- Character storage
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if enaData = '1'
and shiftChars
and phi = '1' then
if badLine then
nextChar(7 downto 0) <= di;
nextChar(11 downto 8) <= diColor;
else
nextChar <= charStore(38);
end if;
charStore <= charStore(37 downto 0) & nextChar;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Sprite base pointer (MPtr)
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if phi = '0'
and enaData = '1'
and vicCycle = cycleSpriteA then
MPtr <= (others => '1');
if MActive(to_integer(sprite)) then
MPtr <= di;
end if;
-- If refresh counter is not emulated we don't care about
-- MPtr having the correct value in idle state.
if not emulateRefresh then
MPtr <= di;
end if;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Refresh counter
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
vicRefresh <= '0';
case vicCycle is
when cycleRefresh1 | cycleRefresh2 | cycleRefresh3 | cycleRefresh4 | cycleRefresh5 =>
vicRefresh <= '1';
if phi = '0'
and enaData = '1'
and baSync = '0' then
refreshCounter <= refreshCounter - 1;
end if;
when others =>
null;
end case;
if lastLineFlag then
refreshCounter <= (others => '1');
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Generate Raster Enable
-- -----------------------------------------------------------------------
process(clk)
begin
-- Enable screen and character display.
-- This is only possible in line 48 on the VIC-II.
-- On other lines any DEN changes are ignored.
if rising_edge(clk) then
if (rasterY = 48) and (DEN = '1') then
rasterEnable <= '1';
end if;
if (rasterY = 248) then
rasterEnable <= '0';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- BA generator (Text/Bitmap)
-- -----------------------------------------------------------------------
--
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -