Apple-II_MiSTer/video_generator.vhd

222 lines
6.9 KiB
VHDL

-------------------------------------------------------------------------------
--
-- Apple ][ Video Generation Logic
--
-- Stephen A. Edwards, sedwards@cs.columbia.edu
--
-- This takes data from memory and various mode switches to produce the
-- serial one-bit video data stream.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity video_generator is
port (
CLK_14M : in std_logic; -- 14.31818 MHz master clock
CLK_7M : in std_logic;
AX : in std_logic;
CAS_N : in std_logic;
TEXT_MODE : in std_logic;
PAGE2 : in std_logic;
HIRES_MODE : in std_logic;
MIXED_MODE : in std_logic;
H0 : in std_logic;
VA : in std_logic;
VB : in std_logic;
VC : in std_logic;
V2 : in std_logic;
V4 : in std_logic;
BLANK : in std_logic;
DL : in unsigned(7 downto 0); -- Data from RAM
LDPS_N : in std_logic;
LD194 : in std_logic;
FLASH_CLK : in std_logic; -- Low-frequency flashing text clock
HIRES : out std_logic;
VIDEO : out std_logic;
COLOR_LINE : out std_logic
);
end video_generator;
architecture rtl of video_generator is
signal char_rom_addr : unsigned(8 downto 0);
signal char_rom_out : unsigned(4 downto 0);
signal text_shiftreg : unsigned(5 downto 0);
signal invert_character : std_logic;
signal text_pixel : std_logic; -- B2 p11
signal blank_delayed : std_logic;
signal video_sig : std_logic; -- output of B10 p5
signal graph_shiftreg : unsigned(7 downto 0);
signal graphics_time_1, graphics_time_2,
graphics_time_3 : std_logic; -- B5 p2, B8 p15, B8 p2
signal lores_time : std_logic; -- A11 p6
signal pixel_select : std_logic_vector(1 downto 0); -- A10 p14, A10 p15
signal hires_delayed : std_logic; -- A11 p9
begin
-----------------------------------------------------------------------------
--
-- Text Mode Circuitry
--
-- The character ROM drives a parallel-to-serial shift register
-- whose output is selectively inverted by inverted or flashing text
--
-----------------------------------------------------------------------------
char_rom_addr <= DL(5 downto 0) & VC & VB & VA;
thecharrom : entity work.character_rom
port map(
addr => char_rom_addr,
clk => CLK_14M, -- FIXME: a lower frequency?
dout => char_rom_out
);
-- Parallel-to-serial shifter for text mode
-- The Apple actually used LDPS_N as the clock, not 14M; this is equivalent
A3_74166: process (CLK_14M)
begin
if rising_edge(CLK_14M) then
if CLK_7M = '0' then
if LDPS_N = '0' then -- load
text_shiftreg <= char_rom_out & "0";
else -- shift
text_shiftreg <= '0' & text_shiftreg(5 downto 1);
end if;
end if;
end if;
end process;
-- Latch and decoder for flashing/inverted text
-- Comprises part of B11, B13, and A10
flash_invert : process (CLK_14M)
begin
if rising_edge(CLK_14M) then
if LD194 = '0' then
invert_character <= not (DL(7) or (DL(6) and FLASH_CLK));
end if;
end if;
end process;
text_pixel <= text_shiftreg(0) xor invert_character;
-----------------------------------------------------------------------------
--
-- Lores and Hires Mode Circuitry
--
-- An eight-bit shift register that either shifts (hires mode) or rotates
-- the two nibbles (lores) followed by a mux that selects the video
-- data from the text mode display, the hires shift register (possibly
-- delayed by a 14M clock pulse), or one of the bits in the lores shift
-- register.
--
-----------------------------------------------------------------------------
-- Original Apple clocked this shift register on the rising edge of RAS_N
B5B8_74LS174 : process (CLK_14M)
begin
if rising_edge(CLK_14M) then
if AX = '1' and CAS_N = '0' then
graphics_time_3 <= graphics_time_2;
graphics_time_2 <= graphics_time_1;
graphics_time_1 <= not (TEXT_MODE or (V2 and V4 and MIXED_MODE));
end if;
end if;
end process;
COLOR_LINE <= graphics_time_1;
HIRES <= HIRES_MODE and graphics_time_3; -- to address generator
lores_time <= not HIRES_MODE and graphics_time_3;
A8A10_74LS194 : process (CLK_14M)
begin
if rising_edge(CLK_14M) then
if LD194 = '0' then
if lores_time = '1' then -- LORES mode
pixel_select <= VC & H0;
else -- HIRES mode
pixel_select <= graphics_time_1 & DL(7);
end if;
end if;
end if;
end process;
-- Shift hires pixels by one 14M cycle to get orange and blue
A11_74LS74 : process (CLK_14M)
begin
if rising_edge(CLK_14M) then
hires_delayed <= graph_shiftreg(0);
end if;
end process;
-- A pair of four-bit universal shift registers that either
-- shift the whole byte (hires mode) or rotate the two nibbles (lores mode)
B4B9_74LS194 : process (CLK_14M)
begin
if rising_edge(CLK_14M) then
if LD194 = '0' then
graph_shiftreg <= DL;
else
if lores_time = '1' then -- LORES configuration
graph_shiftreg <= graph_shiftreg(4) & graph_shiftreg(7 downto 5) &
graph_shiftreg(0) & graph_shiftreg(3 downto 1);
else -- HIRES configuration
if CLK_7M = '0' then
graph_shiftreg <= graph_shiftreg(4) & graph_shiftreg(7 downto 1);
end if;
end if;
end if;
end if;
end process;
-- Synchronize BLANK to LD194
A10_74LS194: process (CLK_14M)
begin
if rising_edge(CLK_14M) then
if LD194 = '0' then
blank_delayed <= BLANK;
end if;
end if;
end process;
-- Video output mux and flip-flop
A9B10_74LS151 : process (CLK_14M)
begin
if rising_edge(CLK_14M) then
if blank_delayed = '0' then
if lores_time = '1' then -- LORES mode
case pixel_select is
when "00" => video_sig <= graph_shiftreg(0);
when "01" => video_sig <= graph_shiftreg(2);
when "10" => video_sig <= graph_shiftreg(4);
when "11" => video_sig <= graph_shiftreg(6);
when others => video_sig <= 'X';
end case;
else
if pixel_select(1) = '0' then -- TEXT mode
video_sig <= text_pixel;
else -- HIRES mode
if pixel_select(0) = '1' then
video_sig <= hires_delayed;
else
video_sig <= graph_shiftreg(0);
end if;
end if;
end if;
else
video_sig <= '0';
end if;
end if;
end process;
VIDEO <= video_sig;
end rtl;