guimauve2ooo/vga_controller.vhd
2013-11-13 22:47:08 +01:00

348 lines
10 KiB
VHDL

-------------------------------------------------------------------------------
--
-- A VGA line-doubler for an Apple ][
--
-- Stephen A. Edwards, sedwards.cs.columbia.edu
--
-- The Apple ][ uses a 14.31818 MHz master clock. It outputs a new
-- horizontal line every 65 * 14 + 2 = 912 14M cycles. The extra two
-- are from the "extended cycle" used to keep the 3.579545 MHz
-- colorburst signal in sync. Of these, 40 * 14 = 560 are active video.
--
-- In graphics mode, the Apple effectively generates 140 four-bit pixels
-- output serially (i.e., with 3.579545 MHz pixel clock). In text mode,
-- it generates 280 one-bit pixels (i.e., with a 7.15909 MHz pixel clock).
--
-- We capture 140 four-bit nibbles for each line and interpret them in
-- one of the two modes. In graphics mode, each is displayed as a
-- single pixel of one of 16 colors. In text mode, each is displayed
-- as two black or white pixels.
--
-- The VGA display is nominally 640 X 480, but we use a 14.31818 MHz
-- dot clock. To stay in sync with the Apple, we generate a new line
-- every 912 / 2 = 456 14M cycles= 31.8 us, a 31.4 kHz horizontal
-- refresh rate. Of these, 280 will be active video.
--
-- One set of suggested VGA timings:
--
-- ______________________ ________
-- ________| VIDEO |________| VIDEO
-- |-C-|----------D-----------|-E-|
-- __ ______________________________ ___________
-- |_| |_|
-- |B|
-- |---------------A----------------|
--
-- A = 31.77 us Scanline time
-- B = 3.77 us Horizontal sync time
-- C = 1.89 us Back porch
-- D = 25.17 us Active video
-- E = 0.94 us Front porch
--
-- We use A = 456 / 14.31818 MHz = 31.84 us
-- B = 54 / 14.31818 MHz = 3.77 us
-- C = 106 / 14.31818 MHz = 7.40 us
-- D = 280 / 14.31818 MHz = 19.56 us
-- E = 16 / 14.31818 MHz = 1.12 us
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity vga_controller is
port (
CLK_14M : in std_logic; -- 14.31818 MHz master clock
nVIDEO : in std_logic;
COLOR_LINE : in std_logic;
CBL : in std_logic;
SRAM_nWE : out std_logic;
SRAM_nOE : out std_logic;
SRAM_nCE : out std_logic;
SRAM_addr : out unsigned(8 downto 0);
SRAM_data : inout unsigned(3 downto 0);
VGA_HS : out std_logic; -- Active low
VGA_VS : out std_logic; -- Active low
VGA_R : out std_logic_vector(1 downto 0);
VGA_G : out std_logic_vector(1 downto 0);
VGA_B : out std_logic_vector(1 downto 0);
MODE : in std_logic
);
end vga_controller;
architecture rtl of vga_controller is
--GE
signal HBL : std_logic := '0';
signal VBL : std_logic := '0';
signal SRAM_rd_data : unsigned(5 downto 0);
signal SRAM_wr_data : unsigned(3 downto 0);
signal SRAM_nWEi : std_logic;
signal SRAM_nOEi : std_logic;
signal SRAM_nCEi : std_logic;
signal RCOL : std_logic_vector(1 downto 0) := "00";
signal GCOL : std_logic_vector(1 downto 0) := "00";
signal BCOL : std_logic_vector(1 downto 0) := "00";
signal R : std_logic_vector(1 downto 0);
signal G : std_logic_vector(1 downto 0);
signal B : std_logic_vector(1 downto 0);
signal PIXPAT : unsigned(3 downto 0);
signal RAMPIXPAT : unsigned(5 downto 0);
signal COLPAT : unsigned(3 downto 0);
signal TEXT : std_logic;
signal ram_write_addr : unsigned(8 downto 0);
signal ram_we : std_logic;
signal ram_read_addr : unsigned(8 downto 0);
signal hcount : unsigned(9 downto 0);
signal hcount2 : unsigned(9 downto 0);
--GE signal vcount : unsigned(5 downto 0);
signal vcount : unsigned(6 downto 0);
signal even_line : std_logic := '0';
signal hactive : std_logic;
constant VGA_SCANLINE : integer := 456; -- Must be 456 (set by the Apple)
constant VGA_HSYNC : integer := 54;
constant VGA_BACK_PORCH : integer := 66;
constant VGA_ACTIVE : integer := 282; -- Must be 280 (set by the Apple)
constant VGA_FRONT_PORCH : integer := 54;
-- VGA_HSYNC + VGA_BACK_PORCH + VGA_ACTIVE + VGA_FRONT_PORCH = VGA_SCANLINE
--GE (org) constant VBL_TO_VSYNC : integer := 33;
--GE constant VBL_TO_VSYNC : integer := 80;
constant VBL_TO_VSYNC : integer := 55;
constant VGA_VSYNC_LINES : integer := 3;
signal VGA_VS_I, VGA_HS_I : std_logic;
signal video_active : std_logic;
signal vbl_delayed : std_logic;
signal color_line_delayed_1, color_line_delayed_2 : std_logic;
--GE 10/02/2009
signal cbl_last : std_logic;
signal cbl_count : unsigned(9 downto 0);
begin
--GE 10/02/2009
blank_sep2 : process(CLK_14M, CBL, cbl_last, cbl_count)
begin
if falling_edge(CLK_14M) then
cbl_count <= cbl_count + 1;
cbl_last <= CBL;
if (cbl_last = '0' and CBL = '1') then
cbl_count <= "1000100101"; -- 549
end if;
if (cbl_count = 911) then
cbl_count <= (others => '0');
VBL <= CBL;
color_line_delayed_2 <= color_line_delayed_1;
color_line_delayed_1 <= COLOR_LINE;
vbl_delayed <= VBL;
if VBL = '1' then
even_line <= '0';
vcount <= vcount + 1;
else
vcount <= (others => '0');
even_line <= not even_line;
end if;
end if;
if (cbl_count >= 549) and (cbl_count <= 899) then
HBL <= '1';
else
HBL <= '0';
end if;
end if;
end process;
hcount <= cbl_count;
hsync_gen : process (CLK_14M)
begin
if falling_edge(CLK_14M) then
if hcount = VGA_ACTIVE + VGA_FRONT_PORCH or
hcount = VGA_SCANLINE + VGA_ACTIVE + VGA_FRONT_PORCH then
VGA_HS_I <= '0';
elsif hcount = VGA_ACTIVE + VGA_FRONT_PORCH + VGA_HSYNC or
hcount = VGA_SCANLINE + VGA_ACTIVE + VGA_FRONT_PORCH + VGA_HSYNC then
VGA_HS_I <= '1';
end if;
if hcount = VGA_SCANLINE - 1 or
hcount = VGA_SCANLINE + VGA_SCANLINE - 1 then
hactive <= '1';
elsif hcount = VGA_ACTIVE or
hcount = VGA_ACTIVE + VGA_SCANLINE then
hactive <= '0';
end if;
end if;
end process hsync_gen;
VGA_HS <= VGA_HS_I;
vsync_gen : process (CLK_14M)
begin
if falling_edge(CLK_14M) then
if vcount = VBL_TO_VSYNC then
VGA_VS_I <= '0';
elsif vcount = VBL_TO_VSYNC + VGA_VSYNC_LINES then
VGA_VS_I <= '1';
end if;
end if;
end process vsync_gen;
VGA_VS <= VGA_VS_I;
-- Shift in the incoming bits to reconstruct four-bit groups
input_shift_register : process (CLK_14M)
begin
if falling_edge(CLK_14M) then
PIXPAT <= PIXPAT(2 downto 0) & nVIDEO;
end if;
end process input_shift_register;
hcount2 <= hcount - VGA_SCANLINE;
ram_read_addr <=
even_line & hcount(8 downto 1) when hcount < VGA_SCANLINE else
even_line & hcount2(8 downto 1);
ram_write_addr <= (not even_line) & hcount(9 downto 2);
ram_we <= '1' when hcount(1 downto 0) = "00" else '0';
video_active <= hactive and not vbl_delayed;
-- RGB values from Linards Ticmanis,
-- http://newsgroups.derkeiler.com/Archive/Comp/comp.sys.apple2/2005-09/msg00534.html
colorgen: process(COLPAT)
begin
case COLPAT is
when "1110" => -- 1 - 0x90 17 40
RCOL <= "10";
GCOL <= "00";
BCOL <= "01";
when "0111" => -- 2 - 0x40 2c a5
RCOL <= "01";
GCOL <= "00";
BCOL <= "10";
when "0110" => -- 3 - 0xd0 43 e5
RCOL <= "11";
GCOL <= "01";
BCOL <= "11";
when "1011" => -- 4 - 0x00 69 40
RCOL <= "00";
GCOL <= "01";
BCOL <= "01";
when "1010" => -- 5 - 0x80 80 80
RCOL <= "10";
GCOL <= "10";
BCOL <= "10";
when "0011" => -- 6 - 0x2f 95 e5
RCOL <= "00";
GCOL <= "10";
BCOL <= "11";
when "0010" => -- 7 - 0xbf ab ff
RCOL <= "11";
GCOL <= "10";
BCOL <= "11";
when "1101" => -- 8 - 0x40 54 00
RCOL <= "01";
GCOL <= "01";
BCOL <= "00";
when "1100" => -- 9 - 0xd0 6a 1a
RCOL <= "11";
GCOL <= "01";
BCOL <= "00";
when "0101" => -- 10 - 0x80 80 80
RCOL <= "01";
GCOL <= "01";
BCOL <= "01";
when "0100" => -- 11 - 0xff 96 bf
RCOL <= "11";
GCOL <= "10";
BCOL <= "11";
when "1001" => -- 12 - 0x2f bc 1a
RCOL <= "00";
GCOL <= "11";
BCOL <= "00";
when "1000" => -- 13 - 0xbf d3 5a
RCOL <= "11";
GCOL <= "11";
BCOL <= "01";
when "0001" => -- 14 - 0x6f e8 bf
RCOL <= "01";
GCOL <= "11";
BCOL <= "11";
when "0000" => -- 15 - 0xff ff ff
RCOL <= "11";
GCOL <= "11";
BCOL <= "11";
when others => -- 0 - 0x00 00 00
RCOL <= "00";
GCOL <= "00";
BCOL <= "00";
end case;
end process;
TEXT <= '1' when hcount(0) = '0' and CLK_14M = '0' and RAMPIXPAT(3) = '0'
else '1' when hcount(0) = '0' and CLK_14M = '1' and RAMPIXPAT(2) = '0'
else '1' when hcount(0) = '1' and CLK_14M = '0' and RAMPIXPAT(1) = '0'
else '1' when hcount(0) = '1' and CLK_14M = '1' and RAMPIXPAT(0) = '0'
else '0';
COLPAT <= RAMPIXPAT(3 downto 0) when hcount(0) = '1'
else RAMPIXPAT(3 downto 2) & RAMPIXPAT(5 downto 4);
--GE
SRAM_addr <= ram_read_addr when hcount(0) = '1' else ram_write_addr;
SRAM_nWEi <= not ram_we;
SRAM_nOEi <= '0' when hcount(0) = '1' else '1';
SRAM_nCEi <= CLK_14M;
process(CLK_14M)
begin
if rising_edge(CLK_14M) and SRAM_nOEi = '0' then
SRAM_rd_data <= SRAM_rd_data(1 downto 0) & SRAM_data;
end if;
end process;
process(CLK_14M)
begin
if falling_edge(CLK_14M) then
RAMPIXPAT <= SRAM_rd_data;
end if;
end process;
SRAM_wr_data <= PIXPAT;
SRAM_data <= SRAM_wr_data when SRAM_nCEi = '0' and SRAM_nWEi = '0' else "ZZZZ";
SRAM_nCE <= SRAM_nCEi;
SRAM_nOE <= SRAM_nOEi;
SRAM_nWE <= SRAM_nWEi;
R <= RCOL when video_active = '1' and color_line_delayed_2 = '1'
else TEXT & TEXT when video_active = '1' and color_line_delayed_2 = '0'
else "00";
G <= GCOL when video_active = '1' and color_line_delayed_2 = '1'
else TEXT & TEXT when video_active = '1' and color_line_delayed_2 = '0'
else "00";
B <= BCOL when video_active = '1' and color_line_delayed_2 = '1'
else TEXT & TEXT when video_active = '1' and color_line_delayed_2 = '0'
else "00";
VGA_R <= R when MODE = '1' else "00";
VGA_G <= G when MODE = '1' else TEXT & TEXT when video_active = '1' else "00";
VGA_B <= B when MODE = '1' else "00";
end rtl;