📄 video_vicii_656x_a.vhd
字号:
-- For Text/Bitmap BA goes low 3 cycles before real access. So BA starts
-- going low during refresh2 state. See diagram below for timing:
--
-- X 0 0 0 0 0
-- 0 0 0 0 1
-- 0 4 8 C 0
--
-- phi ___ ___ ___ ___ ___ ___ ___ ___...
-- ___ ___ ___ ___ ___ ___ ___ ...
--
-- | | | | | | |...
-- rfr2 rfr3 rfr4 rfr5 char1 char2 char3
--
-- BA _______
-- \\\_______________________________________
-- | 1 | 2 | 3 |
--
-- BACnt 000 001 | 010 | 011 | 100 100 100 ...
--
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if phi = '0' then
baChars <= '1';
case vicCycle is
when cycleRefresh2 | cycleRefresh3 | cycleRefresh4 | cycleRefresh5 =>
if badLine then
baChars <= '0';
end if;
when others =>
if rasterX(9 downto 3) < "0101000"
and badLine then
baChars <= '0';
end if;
end case;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- BA generator (Sprites)
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if phi = '0' then
if sprite = 1 then
baSprite04 <= '1';
end if;
if sprite = 2 then
baSprite15 <= '1';
end if;
if sprite = 3 then
baSprite26 <= '1';
end if;
if sprite = 4 then
baSprite37 <= '1';
end if;
if sprite = 5 then
baSprite04 <= '1';
end if;
if sprite = 6 then
baSprite15 <= '1';
end if;
if sprite = 7 then
baSprite26 <= '1';
end if;
if vicCycle = cycleRefresh1 then
baSprite37 <= '1';
end if;
if MActive(0) and (vicCycle = cycleCalcSprites) then
baSprite04 <= '0';
end if;
if MActive(1) and (vicCycle = cycleSpriteBa2) then
baSprite15 <= '0';
end if;
if MActive(2) and (vicCycle = cycleSpriteB) and (sprite = 0) then
baSprite26 <= '0';
end if;
if MActive(3) and (vicCycle = cycleSpriteB) and (sprite = 1) then
baSprite37 <= '0';
end if;
if MActive(4) and (vicCycle = cycleSpriteB) and (sprite = 2) then
baSprite04 <= '0';
end if;
if MActive(5) and (vicCycle = cycleSpriteB) and (sprite = 3) then
baSprite15 <= '0';
end if;
if MActive(6) and (vicCycle = cycleSpriteB) and (sprite = 4) then
baSprite26 <= '0';
end if;
if MActive(7) and (vicCycle = cycleSpriteB) and (sprite = 5) then
baSprite37 <= '0';
end if;
end if;
end if;
end process;
baLoc <= baChars and baSprite04 and baSprite15 and baSprite26 and baSprite37;
-- -----------------------------------------------------------------------
-- Address valid?
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
addrValid <= '0';
if phi = '0'
or baCnt(2) = '1' then
addrValid <= '1';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Generate ShiftChars flag
-- -----------------------------------------------------------------------
process(rasterX)
begin
shiftChars <= false;
if rasterX(9 downto 3) > "0000000"
and rasterX(9 downto 3) < "0101001" then
shiftChars <= true;
end if;
end process;
-- -----------------------------------------------------------------------
-- RowCounter and ColCounter
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if phi = '0'
and enaData = '1'
and baSync = '0' then
if shiftChars
and idle = '0' then
colCounter <= colCounter + 1;
end if;
case vicCycle is
when cycleRefresh4 =>
colCounter <= colRestart;
if badline then
rowCounter <= (others => '0');
end if;
when cycleSpriteA =>
if sprite = "000" then
if rowCounter = 7 then
colRestart <= colCounter;
idle <= '1';
else
rowCounter <= rowCounter + 1;
end if;
if badline then
rowCounter <= rowCounter + 1;
end if;
end if;
when others =>
null;
end case;
if lastLineFlag then
-- Reset column counter outside visible range.
colRestart <= (others => '0');
end if;
-- Set display mode (leave idle-mode) as soon as
-- there is a badline condition.
if badline then
idle <= '0';
end if;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- X/Y Raster counter
-- -----------------------------------------------------------------------
rasterCounters: process(clk)
begin
if rising_edge(clk) then
if enaPixel = '1' then
rasterX(2 downto 0) <= rasterX(2 downto 0) + 1;
end if;
if phi = '0'
and enaData = '1'
and baSync = '0' then
rasterX(9 downto 3) <= rasterX(9 downto 3) + 1;
rasterX(2 downto 0) <= (others => '0');
if vicCycle = cycleRefresh4 then
rasterX <= (others => '0');
end if;
end if;
if phi = '1'
and enaData = '1'
and baSync = '0' then
beyondFrameFlag <= false;
if (vicCycle = cycleSpriteB)
and (sprite = 2) then
rasterY <= rasterY + 1;
beyondFrameFlag <= lastLineFlag;
end if;
if beyondFrameFlag then
rasterY <= (others => '0');
end if;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Raster IRQ
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
if phi = '1'
and enaData = '1'
and baSync = '0'
and (vicCycle = cycleSpriteB)
and (sprite = 2) then
rasterIrqDone <= '0';
end if;
if resetRasterIrq = '1' then
IRST <= '0';
end if;
if (rasterIrqDone = '0')
and (rasterY = rasterCmp) then
rasterIrqDone <= '1';
IRST <= '1';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Light pen
-- -----------------------------------------------------------------------
-- On a negative edge on the LP input, the current position of the raster beam
-- is latched in the registers LPX ($d013) and LPY ($d014). LPX contains the
-- upper 8 bits (of 9) of the X position and LPY the lower 8 bits (likewise of
-- 9) of the Y position. So the horizontal resolution of the light pen is
-- limited to 2 pixels.
-- Only one negative edge on LP is recognized per frame. If multiple edges
-- occur on LP, all following ones are ignored. The trigger is not released
-- until the next vertical blanking interval.
-- -----------------------------------------------------------------------
lightPen: process(clk)
begin
if rising_edge(clk) then
if emulateLightpen then
if resetLightPenIrq = '1' then
-- Reset light pen interrupt
ILP <= '0';
end if;
if lastLineFlag then
-- Reset lightpen state at beginning of frame
lightPenHit <= '0';
elsif (lightPenHit = '0') and (lp_n = '0') then
-- One hit/frame
lightPenHit <= '1';
-- Toggle Interrupt
ILP <= '1';
-- Store position of beam
lpx <= rasterX(8 downto 1);
lpy <= rasterY(7 downto 0);
end if;
else
ILP <= '0';
lpx <= (others => '1');
lpy <= (others => '1');
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- VSync
-- -----------------------------------------------------------------------
doVBlanking: process(clk, mode6569, mode6567old, mode6567R8)
variable rasterBlank : integer range 0 to 300;
begin
rasterBlank := 300;
if (mode6567old or mode6567R8) = '1' then
rasterBlank := 12;
end if;
if rising_edge(clk) then
vBlanking <= '0';
if rasterY = rasterBlank then
vBlanking <= '1';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- HSync
-- -----------------------------------------------------------------------
doHBlanking: process(clk)
begin
if rising_edge(clk) then
if sprite = 3 then
hBlack <= '1';
end if;
if vicCycle = cycleRefresh1 then
hBlack <= '0';
end if;
if sprite = 5 then
hBlanking <= '1';
else
hBlanking <= '0';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Borders
-- -----------------------------------------------------------------------
calcBorders: process(clk)
variable newTBBorder: std_logic;
begin
if rising_edge(clk) then
if enaPixel = '1' then
--
-- Calc top/bottom border
newTBBorder := TBBorder;
-- if (rasterY = 55) and (RSEL = '0') and (rasterEnable = '1') then
if (rasterY = 55) and (rasterEnable = '1') then
newTBBorder := '0';
end if;
if (rasterY = 51) and (RSEL = '1') and (rasterEnable = '1') then
newTBBorder := '0';
end if;
if (rasterY = 247) and (RSEL = '0') then
newTBBorder := '1';
end if;
if (rasterY = 251) and (RSEL = '1') then
newTBBorder := '1';
end if;
--
-- Calc left/right border
if (rasterX = (31+1)) and (CSEL = '0') then
LRBorder <= newTBBorder;
TBBorder <= newTBBorder;
end if;
if (rasterX = (24+1)) and (CSEL = '1') then
LRBorder <= newTBBorder;
TBBorder <= newTBBorder;
end if;
if (rasterX = (335+1)) and (CSEL = '0') then
LRBorder <= '1';
end if;
if (rasterX = (344+1)) and (CSEL = '1') then
LRBorder <= '1';
end if;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Pixel generator for Text/Bitmap screen
-- -----------------------------------------------------------------------
calcBitmap: process(clk)
variable multiColor : std_logic;
begin
if rising_edge(clk) then
if enaPixel = '1' then
--
-- Toggle flipflop for multicolor 2-bits shift.
shifting_ff <= not shifting_ff;
--
-- Multicolor mode is active with MCM, but for character
-- mode it depends on bit3 of color ram too.
multiColor := MCM and (BMM or ECM or shiftingChar(11));
--
-- Reload shift register when xscroll=rasterX
-- otherwise shift pixels
if xscroll = rasterX(2 downto 0) then
shifting_ff <= '0';
shiftingChar <= waitingChar;
shiftingPixels <= waitingPixels;
elsif multiColor = '0' then
shiftingPixels <= shiftingPixels(6 downto 0) & '0';
elsif shifting_ff = '1' then
shiftingPixels <= shiftingPixels(5 downto 0) & "00";
end if;
--
-- Calculate if pixel is in foreground or background
pixelBgFlag <= shiftingPixels(7);
--
-- Calculate color of next pixel
pixelColor <= B0C;
if (BMM = '0') and (ECM='0') then
if (multiColor = '0') then
-- normal character mode
if shiftingPixels(7) = '1' then
pixelColor <= shiftingChar(11 downto 8);
end if;
else
-- multi-color character mode
case shiftingPixels(7 downto 6) is
when "01" => pixelColor <= B1C;
when "10" => pixelColor <= B2C;
when "11" => pixelColor <= '0' & shiftingChar(10 downto 8);
when others => null;
end case;
end if;
elsif (MCM = '0') and (BMM = '0') and (ECM='1') then
-- extended-color character mode
-- multiple background colors but only 64 characters
if shiftingPixels(7) = '1' then
pixelColor <= shiftingChar(11 downto 8);
else
case shiftingChar(7 downto 6) is
when "01" => pixelColor <= B1C;
when "10" => pixelColor <= B2C;
when "11" => pixelColor <= B3C;
when others => null;
end case;
end if;
elsif emulateGraphics and (MCM = '0') and (BMM = '1') and (ECM='0') then
-- highres bitmap mode
if shiftingPixels(7) = '1' then
pixelColor <= shiftingChar(7 downto 4);
else
pixelColor <= shiftingChar(3 downto 0);
end if;
elsif emulateGraphics and (MCM = '1') and (BMM = '1') and (ECM='0') then
-- Multi-color bitmap mode
case shiftingPixels(7 downto 6) is
when "01" => pixelColor <= shiftingChar(7 downto 4);
when "10" => pixelColor <= shiftingChar(3 downto 0);
when "11" => pixelColor <= shiftingChar(11 downto 8);
when others => null;
end case;
else
-- illegal display mode, the output is black
pixelColor <= "0000";
end if;
end if;
--
-- Store fetched pixels, until current pixels are displayed
-- and shift-register is empty.
if enaData = '1'
and phi = '0' then
readPixels <= (others => '0');
if shiftChars then
readPixels <= di;
readChar <= (others => '0');
if idle = '0' then
readChar <= nextChar;
end if;
end if;
-- Store the characters until shiftregister is empty
waitingPixels <= readPixels;
waitingChar <= readChar;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -