Project

General

Profile

1 markw
---------------------------------------------------------------------------
-- (c) 2013 mark watson
-- I am happy for anyone to use this for non-commercial use.
-- If my vhdl files are used commercially or otherwise sold,
-- please contact me for explicit permission at scrameta (gmail).
-- This applies for source and binary form and derived works.
---------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;

ENTITY scandoubler IS
80 markw
GENERIC
(
video_bits : integer := 4
);
1 markw
PORT
(
CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;

VGA : IN STD_LOGIC;
COMPOSITE_ON_HSYNC : in std_logic;

colour_enable : in std_logic;
doubled_enable : in std_logic;

-- GTIA interface
colour_in : in std_logic_vector(7 downto 0);
vsync_in : in std_logic;
hsync_in : in std_logic;

-- TO TV...
80 markw
R : OUT STD_LOGIC_vector(video_bits-1 downto 0);
G : OUT STD_LOGIC_vector(video_bits-1 downto 0);
B : OUT STD_LOGIC_vector(video_bits-1 downto 0);
1 markw
VSYNC : out std_logic;
HSYNC : out std_logic
);
END scandoubler;

ARCHITECTURE vhdl OF scandoubler IS

COMPONENT gtia_palette IS
PORT
(
ATARI_COLOUR : IN STD_LOGIC_VECTOR(7 downto 0);

R_next : OUT STD_LOGIC_VECTOR(7 downto 0);
G_next : OUT STD_LOGIC_VECTOR(7 downto 0);
B_next : OUT STD_LOGIC_VECTOR(7 downto 0)
);
END component;

-- component reg_file IS
-- generic
-- (
-- BYTES : natural := 1;
-- WIDTH : natural := 1
-- );
-- PORT
-- (
-- CLK : IN STD_LOGIC;
-- ADDR : IN STD_LOGIC_VECTOR(width-1 DOWNTO 0);
-- DATA_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
-- WR_EN : IN STD_LOGIC;
--
-- DATA_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
-- );
-- END component;

component scandouble_ram_infer IS
PORT
(
clock: IN std_logic;
data: IN std_logic_vector (7 DOWNTO 0);
address: IN integer RANGE 0 to 1824;
we: IN std_logic;
q: OUT std_logic_vector (7 DOWNTO 0)
);
END component;

component delay_line IS
generic(COUNT : natural := 1);
PORT
(
CLK : IN STD_LOGIC;
SYNC_RESET : IN STD_LOGIC;
DATA_IN : IN STD_LOGIC;
ENABLE : IN STD_LOGIC; -- i.e. shift on this clock
RESET_N : IN STD_LOGIC;

DATA_OUT : OUT STD_LOGIC
);
END component;

signal colour_next : std_logic_vector(7 downto 0);
signal colour_reg : std_logic_vector(7 downto 0);

signal vsync_next : std_logic;
signal vsync_reg : std_logic;

signal hsync_next : std_logic;
signal hsync_reg : std_logic;

signal r_next : std_logic_vector(7 downto 0);
signal g_next : std_logic_vector(7 downto 0);
signal b_next : std_logic_vector(7 downto 0);
signal r_reg : std_logic_vector(7 downto 0);
signal g_reg : std_logic_vector(7 downto 0);
signal b_reg : std_logic_vector(7 downto 0);

signal linea_address : std_logic_vector(10 downto 0);
signal linea_write_enable : std_logic;
signal linea_out : std_logic_vector(7 downto 0);

signal lineb_address : std_logic_vector(10 downto 0);
signal lineb_write_enable : std_logic;
signal lineb_out : std_logic_vector(7 downto 0);

signal input_address_next : std_logic_vector(10 downto 0);
signal input_address_reg : std_logic_vector(10 downto 0);

signal output_address_next : std_logic_vector(10 downto 0);
signal output_address_reg : std_logic_vector(10 downto 0);

signal buffer_select_next : std_logic;
signal buffer_select_reg : std_logic;

signal hsync_in_reg : std_logic;

signal vga_hsync_next : std_logic;
signal vga_hsync_reg : std_logic;
signal vga_hsync_start : std_logic;
signal vga_hsync_end : std_logic;

begin
-- register
process(clk,reset_n)
begin
if (reset_n = '0') then
r_reg <= (others=>'0');
g_reg <= (others=>'0');
b_reg <= (others=>'0');
colour_reg <= (others=>'0');
hsync_reg <= '0';
vsync_reg <= '0';

input_address_reg <= (others=>'0');
output_address_reg <= (others=>'0');

buffer_select_reg <= '0';

vga_hsync_reg <= '0';
elsif (clk'event and clk='1') then
r_reg <= r_next;
g_reg <= g_next;
b_reg <= b_next;
colour_reg <= colour_next;
hsync_reg <= hsync_next;
vsync_reg <= vsync_next;

input_address_reg <= input_address_next;
output_address_reg <= output_address_next;

buffer_select_reg <= buffer_select_next;

hsync_in_reg <= hsync_in;

vga_hsync_reg <= vga_hsync_next;
end if;
end process;

-- TODO - these should use FPGA RAM - at present about 50% of FPGA is taken by these!!!
-- linea : reg_file
--generic map (BYTES=>456,WIDTH=>9)
--port map (clk=>clk,addr=>linea_address,wr_en=>linea_write_enable,data_in=>colour_in,data_out=>linea_out);

--lineb : reg_file
-- generic map (BYTES=>456,WIDTH=>9)
-- port map (clk=>clk,addr=>lineb_address,wr_en=>lineb_write_enable,data_in=>colour_in,data_out=>lineb_out);

linea : scandouble_ram_infer
port map (clock=>clk,address=>to_integer(unsigned(linea_address)),we=>linea_write_enable,data=>colour_in,q=>linea_out);

lineb : scandouble_ram_infer
port map (clock=>clk,address=>to_integer(unsigned(lineb_address)),we=>lineb_write_enable,data=>colour_in,q=>lineb_out);

-- capture
process(input_address_reg,colour_enable,hsync_in,hsync_in_reg,buffer_select_reg)
begin
input_address_next <= input_address_reg;
buffer_select_next <= buffer_select_reg;

linea_write_enable <= '0';
lineb_write_enable <= '0';

if (colour_enable = '1') then
input_address_next <= std_logic_vector(unsigned(input_address_reg)+1);
linea_write_enable <= buffer_select_reg;
lineb_write_enable <= not(buffer_select_reg);
end if;

if (hsync_in = '1' and hsync_in_reg = '0') then
input_address_next <= (others=>'0');
buffer_select_next <= not(buffer_select_reg);
end if;
end process;

-- output
process(vga_hsync_reg,vga_hsync_end,output_address_reg,doubled_enable)
begin
output_address_next <= output_address_reg;
vga_hsync_start<='0';
vga_hsync_next <= vga_hsync_reg;

if (doubled_enable = '1') then
output_address_next <= std_logic_vector(unsigned(output_address_reg)+1);

if (output_address_reg = "111"&X"1F") then
output_address_next <= (others=>'0');
vga_hsync_start <= '1';
vga_hsync_next <= '1';
end if;
end if;

if (vga_hsync_end = '1') then
vga_hsync_next <= '0';
end if;
end process;

linea_address <= input_address_reg when buffer_select_reg='1' else output_address_reg;
lineb_address <= input_address_reg when buffer_select_reg='0' else output_address_reg;

hsync_delay : delay_line
generic map (COUNT=>128)
port map(clk=>clk,sync_reset=>'0',data_in=>vga_hsync_start,enable=>doubled_enable,reset_n=>reset_n,data_out=>vga_hsync_end);

-- display
process(colour_reg,vsync_reg,vga_hsync_reg,hsync_reg,colour_in,vsync_in,hsync_in,colour_enable,doubled_enable,vga,composite_on_hsync,buffer_select_reg,linea_out,lineb_out)
begin
colour_next <= colour_reg;
vsync_next <= vsync_reg;
hsync_next <= hsync_reg;

if (vga = '0') then
-- non-vga mode - pass through
colour_next <= colour_in;
vsync_next <= not(vsync_in);
--hsync_next <= not(hsync_in or vsync_in);
if (composite_on_hsync = '1') then
hsync_next <= not(hsync_in xor vsync_in);
else
hsync_next <= not(hsync_in);
end if;
else
-- vga mode, store all inputs - then play back!
if (buffer_select_reg = '0') then
colour_next <= linea_out; -- todo, smoothly increase/decrease...
else
colour_next <= lineb_out;
end if;

vsync_next <= not(vsync_in);
--hsync_next <= not(vga_hsync_reg);
if (composite_on_hsync = '1') then
hsync_next <= not(vga_hsync_reg xor vsync_in);
else
hsync_next <= not(vga_hsync_reg);
end if;
end if;
end process;

-- colour palette
-- Color Value Color Value
--Black 0, 0 Medium blue 8, 128
--Rust 1, 16 Dark blue 9, 144
--Red-orange 2, 32 Blue-grey 10, 160
--Dark orange 3, 48 Olive green 11, 176
--Red 4, 64 Medium green 12, 192
--Dk lavender 5, 80 Dark green 13, 208
--Cobalt blue 6, 96 Orange-green 14, 224
--Ultramarine 7, 112 Orange 15, 240

-- from altirra
palette1 : entity work.gtia_palette(altirra)
port map (ATARI_COLOUR=>colour_reg, R_next=>R_next, G_next=>G_next, B_next=>B_next);

-- from lao
-- palette2 : entity work.gtia_palette(laoo)
-- port map (ATARI_COLOUR=>COLOUR, R_next=>R_next, G_next=>G_next, B_next=>B_next);

-- output
-- TODO - for DE2, output full 8 bits
80 markw
R <= R_reg(7 downto 8-video_bits);
G <= G_reg(7 downto 8-video_bits);
B <= B_reg(7 downto 8-video_bits);
1 markw
vsync<=vsync_reg;
hsync<=hsync_reg;

end vhdl;