Project

General

Profile

---------------------------------------------------------------------------
-- (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
GENERIC
(
video_bits : integer := 4
);
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;

scanlines_on : in std_logic := '0';
-- GTIA interface
pal : in std_logic;
colour_in : in std_logic_vector(7 downto 0);
vsync_in : in std_logic;
hsync_in : in std_logic;
csync_in : in std_logic;
-- TO TV...
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);
VSYNC : out std_logic;
HSYNC : out std_logic
);
END scandoubler;

ARCHITECTURE vhdl OF scandoubler IS

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_address_integer : integer;
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_address_integer : integer;
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;

signal vga_odd_reg : std_logic;
signal vga_odd_next : std_logic;

signal reset_output_address : 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';

vga_odd_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;

vga_odd_reg <= vga_odd_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_address_integer <= to_integer(unsigned(linea_address));
linea : scandouble_ram_infer
port map (clock=>clk,address=>linea_address_integer,we=>linea_write_enable,data=>colour_in,q=>linea_out);

lineb_address_integer <= to_integer(unsigned(lineb_address));
lineb : scandouble_ram_infer
port map (clock=>clk,address=>lineb_address_integer,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';
reset_output_address <= '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);
reset_output_address <= '1';
end if;
end process;
-- output
process(vga_hsync_reg,vga_hsync_end,output_address_reg,doubled_enable,vga_odd_reg,reset_output_address)
begin
output_address_next <= output_address_reg;
vga_hsync_start<='0';
vga_hsync_next <= vga_hsync_reg;
vga_odd_next <= vga_odd_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';
vga_odd_next <= not(vga_odd_reg);
end if;

if (reset_output_address = '1') then
output_address_next <= (others=>'0');
vga_odd_next <= '1';
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,csync_in,vsync_in,hsync_in,colour_enable,doubled_enable,vga,composite_on_hsync,buffer_select_reg,linea_out,lineb_out, scanlines_on, vga_odd_reg)
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;
--hsync_next <= not(hsync_in or vsync_in);
if (composite_on_hsync = '1') then
--hsync_next <= not(hsync_in xor vsync_in);
hsync_next <= not(csync_in);
vsync_next <='1';
else
hsync_next <= not(hsync_in);
vsync_next <= not(vsync_in);
end if;
else
-- vga mode, store all inputs - then play back!
if (buffer_select_reg = '0') then
if (scanlines_on ='1' and vga_odd_reg='1') then
colour_next(7 downto 4) <= linea_out(7 downto 4);
colour_next(3) <= '0';
colour_next(2 downto 0) <= linea_out(3 downto 1);
else
colour_next <= linea_out;
end if;
else
if (scanlines_on ='1' and vga_odd_reg='1') then
colour_next(7 downto 4) <= lineb_out(7 downto 4);
colour_next(3) <= '0';
colour_next(2 downto 0) <= lineb_out(3 downto 1);
else
colour_next <= lineb_out;
end if;
end if;
--hsync_next <= not(vga_hsync_reg);
if (composite_on_hsync = '1') then
hsync_next <= not(vga_hsync_reg xor vsync_in);
vsync_next <='1';
else
hsync_next <= not(vga_hsync_reg);
vsync_next <= not(vsync_in);
end if;
end if;
end process;

-- colour palette
palette4 : entity work.gtia_palette
port map (PAL=>pal,ATARI_COLOUR=>colour_reg, R_next=>R_next, G_next=>G_next, B_next=>B_next);
-- output
-- TODO - for DE2, output full 8 bits
R <= R_reg(7 downto 8-video_bits);
G <= G_reg(7 downto 8-video_bits);
B <= B_reg(7 downto 8-video_bits);
vsync<=vsync_reg;
hsync<=hsync_reg;

end vhdl;


(13-13/18)