2017-04-24 19:21:18 +00:00
|
|
|
----------------------------------------------------------------------------------
|
|
|
|
-- Engineer: David Banks
|
|
|
|
--
|
|
|
|
-- Create Date: 14/4/2017
|
|
|
|
-- Module Name: RGBtoHDMI CPLD
|
|
|
|
-- Project Name: RGBtoHDMI
|
|
|
|
-- Target Devices: XC9572XL
|
|
|
|
--
|
|
|
|
-- Version: 0.50
|
|
|
|
--
|
|
|
|
----------------------------------------------------------------------------------
|
|
|
|
library ieee;
|
|
|
|
use ieee.std_logic_1164.all;
|
|
|
|
use ieee.numeric_std.all;
|
|
|
|
|
|
|
|
entity RGBtoHDMI is
|
|
|
|
Port (
|
|
|
|
-- From Beeb RGB Connector
|
2018-06-05 16:52:42 +00:00
|
|
|
R0: in std_logic;
|
|
|
|
G0: in std_logic;
|
|
|
|
B0: in std_logic;
|
|
|
|
R1: in std_logic;
|
|
|
|
G1: in std_logic;
|
|
|
|
B1: in std_logic;
|
2017-04-26 17:15:47 +00:00
|
|
|
S: in std_logic;
|
2017-04-24 19:21:18 +00:00
|
|
|
|
|
|
|
-- From Pi
|
|
|
|
clk: in std_logic;
|
2017-04-26 21:19:41 +00:00
|
|
|
mode7: in std_logic;
|
2018-06-05 16:52:42 +00:00
|
|
|
elk: in std_logic;
|
2017-05-24 12:20:06 +00:00
|
|
|
sp_clk: in std_logic;
|
2018-06-06 16:51:11 +00:00
|
|
|
sp_clken: in std_logic;
|
2017-05-24 12:20:06 +00:00
|
|
|
sp_data: in std_logic;
|
2017-04-24 19:21:18 +00:00
|
|
|
|
|
|
|
-- To PI GPIO
|
|
|
|
quad: out std_logic_vector(11 downto 0);
|
|
|
|
psync: out std_logic;
|
2017-04-26 17:15:47 +00:00
|
|
|
csync: out std_logic;
|
2017-04-24 19:21:18 +00:00
|
|
|
|
2018-06-05 16:52:42 +00:00
|
|
|
-- User interface
|
2018-06-05 17:58:11 +00:00
|
|
|
SW1: in std_logic;
|
|
|
|
SW2: in std_logic; -- currently unused
|
|
|
|
SW3: in std_logic; -- currently unused
|
2018-06-06 16:51:11 +00:00
|
|
|
spare: in std_logic; -- currently unused
|
|
|
|
link: in std_logic; -- currently unused
|
2018-06-05 17:58:11 +00:00
|
|
|
LED1: out std_logic;
|
|
|
|
LED2: out std_logic
|
2017-04-24 19:21:18 +00:00
|
|
|
);
|
|
|
|
end RGBtoHDMI;
|
|
|
|
|
|
|
|
architecture Behavorial of RGBtoHDMI is
|
|
|
|
|
2017-04-26 21:19:41 +00:00
|
|
|
-- For Modes 0..6
|
2017-05-24 12:20:06 +00:00
|
|
|
constant default_offset : unsigned(11 downto 0) := to_unsigned(4096 - 64 * 23 + 6, 12);
|
2017-04-26 17:15:47 +00:00
|
|
|
|
2017-05-23 12:03:27 +00:00
|
|
|
-- For Mode 7
|
2017-05-25 18:31:34 +00:00
|
|
|
constant mode7_offset : unsigned(11 downto 0) := to_unsigned(4096 - 96 * 12 + 4, 12);
|
2017-05-24 12:20:06 +00:00
|
|
|
|
|
|
|
-- Sampling points
|
2017-05-25 18:31:34 +00:00
|
|
|
constant INIT_SAMPLING_POINTS : std_logic_vector(20 downto 0) := "011011011011011011011";
|
2017-04-25 17:24:49 +00:00
|
|
|
|
2017-04-24 19:21:18 +00:00
|
|
|
signal shift : std_logic_vector(11 downto 0);
|
|
|
|
|
2017-04-26 17:15:47 +00:00
|
|
|
signal CSYNC1 : std_logic;
|
2017-04-24 19:21:18 +00:00
|
|
|
|
2017-05-24 12:20:06 +00:00
|
|
|
-- The sampling counter runs at 96MHz
|
|
|
|
-- - In modes 0..6 it is 6x the pixel clock
|
|
|
|
-- - In mode 7 it is 8x the pixel clock
|
2017-04-24 19:21:18 +00:00
|
|
|
--
|
|
|
|
-- It serves several purposes:
|
|
|
|
-- 1. Counts the 12us between the rising edge of nCSYNC and the first pixel
|
2017-05-24 12:20:06 +00:00
|
|
|
-- 2. Counts within each pixel (bits 0, 1, 2)
|
|
|
|
-- 3. Counts counts pixels within a quad pixel (bits 3 and 4)
|
|
|
|
-- 4. Handles double buffering of alternative quad pixels (bit 5)
|
2017-04-24 19:21:18 +00:00
|
|
|
--
|
|
|
|
-- At the moment we don't count pixels with the line, the Pi does that
|
2017-05-23 12:03:27 +00:00
|
|
|
signal counter : unsigned(11 downto 0);
|
2017-04-24 19:21:18 +00:00
|
|
|
|
2017-05-25 18:31:34 +00:00
|
|
|
signal counter2 : unsigned(5 downto 3);
|
|
|
|
|
2017-05-24 12:20:06 +00:00
|
|
|
-- Sample point register;
|
|
|
|
--
|
|
|
|
-- In Modes 0..6 each pixel lasts 6 clocks (96MHz / 16MHz). The original
|
|
|
|
-- pixel clock is a clean 16Mhz clock, so only one sample point is needed.
|
|
|
|
--
|
|
|
|
-- In Mode 7 each pixel lasts 8 clocks (96MHz / 12MHz). The original
|
|
|
|
-- pixel clock is a regenerated 6Mhz clock, and both edges are used.
|
|
|
|
-- Due to the way it is generated, there are three distinct phases,
|
|
|
|
-- hence three sampling points are used.
|
2017-05-25 16:23:49 +00:00
|
|
|
signal sp_reg : std_logic_vector(20 downto 0) := INIT_SAMPLING_POINTS;
|
2017-05-24 12:20:06 +00:00
|
|
|
|
|
|
|
-- Break out of sp
|
|
|
|
signal sp : std_logic_vector(2 downto 0);
|
|
|
|
signal mode7_sp_A : std_logic_vector(2 downto 0);
|
|
|
|
signal mode7_sp_B : std_logic_vector(2 downto 0);
|
|
|
|
signal mode7_sp_C : std_logic_vector(2 downto 0);
|
2017-05-25 16:23:49 +00:00
|
|
|
signal mode7_sp_D : std_logic_vector(2 downto 0);
|
|
|
|
signal mode7_sp_E : std_logic_vector(2 downto 0);
|
|
|
|
signal mode7_sp_F : std_logic_vector(2 downto 0);
|
2017-05-24 12:20:06 +00:00
|
|
|
signal default_sp : std_logic_vector(2 downto 0);
|
|
|
|
|
|
|
|
-- Index to allow cycling between A, B and C in Mode 7
|
2017-05-25 16:23:49 +00:00
|
|
|
signal sp_index : std_logic_vector(2 downto 0);
|
2017-05-24 12:20:06 +00:00
|
|
|
|
|
|
|
-- Sample pixel on next clock; pipelined to reducethe number of product terms
|
2018-06-05 16:52:42 +00:00
|
|
|
signal sample : std_logic;
|
2017-05-24 12:20:06 +00:00
|
|
|
|
2018-06-05 16:52:42 +00:00
|
|
|
signal R : std_logic;
|
|
|
|
signal G : std_logic;
|
|
|
|
signal B : std_logic;
|
2017-04-24 19:21:18 +00:00
|
|
|
|
2018-06-05 16:52:42 +00:00
|
|
|
begin
|
2017-04-24 19:21:18 +00:00
|
|
|
|
2018-06-05 16:52:42 +00:00
|
|
|
R <= R1 when elk = '1' else R0;
|
|
|
|
G <= G1 when elk = '1' else G0;
|
|
|
|
B <= B1 when elk = '1' else B0;
|
2018-06-06 13:28:12 +00:00
|
|
|
|
2017-05-24 12:20:06 +00:00
|
|
|
mode7_sp_A <= sp_reg(2 downto 0);
|
|
|
|
mode7_sp_B <= sp_reg(5 downto 3);
|
|
|
|
mode7_sp_C <= sp_reg(8 downto 6);
|
2017-05-25 16:23:49 +00:00
|
|
|
mode7_sp_D <= sp_reg(11 downto 9);
|
|
|
|
mode7_sp_E <= sp_reg(14 downto 12);
|
|
|
|
mode7_sp_F <= sp_reg(17 downto 15);
|
|
|
|
default_sp <= sp_reg(20 downto 18);
|
2017-05-24 12:20:06 +00:00
|
|
|
|
|
|
|
-- Shift the bits in LSB first
|
2018-06-05 17:58:11 +00:00
|
|
|
process(sp_clk, SW1)
|
2017-05-24 12:20:06 +00:00
|
|
|
begin
|
2018-06-06 13:48:51 +00:00
|
|
|
--if SW1 = '0' then
|
|
|
|
-- sp_reg <= INIT_SAMPLING_POINTS;
|
|
|
|
if rising_edge(sp_clk) then
|
2018-06-06 16:51:11 +00:00
|
|
|
if sp_clken = '1' then
|
|
|
|
sp_reg <= sp_data & sp_reg(sp_reg'left downto sp_reg'right + 1);
|
|
|
|
end if;
|
2017-05-24 12:20:06 +00:00
|
|
|
end if;
|
|
|
|
end process;
|
|
|
|
|
2017-04-24 19:21:18 +00:00
|
|
|
process(clk)
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
2017-04-26 17:15:47 +00:00
|
|
|
-- synchronize CSYNC to the sampling clock
|
|
|
|
CSYNC1 <= S;
|
2017-04-24 19:21:18 +00:00
|
|
|
|
2017-05-24 12:20:06 +00:00
|
|
|
-- pipeline sample
|
|
|
|
if counter(2 downto 0) = unsigned(sp) then
|
|
|
|
sample <= '1';
|
|
|
|
else
|
|
|
|
sample <= '0';
|
|
|
|
end if;
|
2017-05-25 18:31:34 +00:00
|
|
|
-- pipeline counter
|
|
|
|
counter2(5 downto 3) <= counter(5 downto 3);
|
2017-05-24 12:20:06 +00:00
|
|
|
|
2017-04-26 17:15:47 +00:00
|
|
|
if CSYNC1 = '0' then
|
|
|
|
-- in the line sync
|
2017-04-25 08:57:21 +00:00
|
|
|
psync <= '0';
|
2017-04-25 10:53:22 +00:00
|
|
|
-- counter is used to find sampling point for first pixel
|
2017-04-26 21:19:41 +00:00
|
|
|
if mode7 = '1' then
|
2017-05-24 12:20:06 +00:00
|
|
|
counter <= mode7_offset;
|
2017-05-25 16:23:49 +00:00
|
|
|
sp_index <= "000";
|
2017-05-24 12:20:06 +00:00
|
|
|
sp <= mode7_sp_A;
|
2017-04-26 21:19:41 +00:00
|
|
|
else
|
2017-05-24 12:20:06 +00:00
|
|
|
counter <= default_offset;
|
2017-05-25 16:23:49 +00:00
|
|
|
sp_index <= "111";
|
2017-05-24 12:20:06 +00:00
|
|
|
sp <= default_sp;
|
2017-04-26 21:19:41 +00:00
|
|
|
end if;
|
2017-04-24 19:21:18 +00:00
|
|
|
else
|
|
|
|
-- within the line
|
2017-05-23 12:03:27 +00:00
|
|
|
if mode7 = '1' then
|
|
|
|
if counter = 63 then
|
|
|
|
counter <= to_unsigned(0, counter'length);
|
|
|
|
else
|
|
|
|
counter <= counter + 1;
|
|
|
|
end if;
|
2017-05-25 18:31:34 +00:00
|
|
|
if counter(2 downto 0) = 7 then
|
2017-05-25 16:23:49 +00:00
|
|
|
case sp_index is
|
|
|
|
when "000" =>
|
|
|
|
sp_index <= "001";
|
|
|
|
sp <= mode7_sp_B;
|
|
|
|
when "001" =>
|
|
|
|
sp_index <= "010";
|
|
|
|
sp <= mode7_sp_C;
|
|
|
|
when "010" =>
|
|
|
|
sp_index <= "011";
|
|
|
|
sp <= mode7_sp_D;
|
|
|
|
when "011" =>
|
|
|
|
sp_index <= "100";
|
|
|
|
sp <= mode7_sp_E;
|
|
|
|
when "100" =>
|
|
|
|
sp_index <= "101";
|
|
|
|
sp <= mode7_sp_F;
|
|
|
|
when others =>
|
|
|
|
sp_index <= "000";
|
|
|
|
sp <= mode7_sp_A;
|
|
|
|
end case;
|
2017-05-24 12:20:06 +00:00
|
|
|
end if;
|
2017-04-24 19:21:18 +00:00
|
|
|
else
|
2017-05-23 12:03:27 +00:00
|
|
|
if counter = 61 then
|
|
|
|
counter <= to_unsigned(0, counter'length);
|
|
|
|
elsif counter(2 downto 0) = 5 then
|
|
|
|
counter <= counter + 3;
|
|
|
|
else
|
|
|
|
counter <= counter + 1;
|
|
|
|
end if;
|
2017-04-24 19:21:18 +00:00
|
|
|
end if;
|
2017-05-23 12:03:27 +00:00
|
|
|
|
|
|
|
if counter(11) = '0' then
|
2017-05-24 12:20:06 +00:00
|
|
|
if sample = '1' then
|
2017-04-24 19:21:18 +00:00
|
|
|
shift <= B & G & R & shift(11 downto 3);
|
2017-05-25 18:31:34 +00:00
|
|
|
if counter2(4 downto 3) = "00" then
|
2017-04-24 19:21:18 +00:00
|
|
|
quad <= shift;
|
2017-05-25 18:31:34 +00:00
|
|
|
psync <= counter2(5);
|
2017-04-24 19:21:18 +00:00
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
else
|
|
|
|
quad <= (others => '0');
|
2017-04-25 08:57:21 +00:00
|
|
|
psync <= '0';
|
2017-04-24 19:21:18 +00:00
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end process;
|
|
|
|
|
2018-06-06 13:28:12 +00:00
|
|
|
csync <= S; -- pass through, as clock might not be running
|
2018-06-05 17:58:11 +00:00
|
|
|
LED1 <= 'Z'; -- allow this to be driven from the Pi
|
2018-06-06 13:28:12 +00:00
|
|
|
LED2 <= not(mode7);
|
2017-05-25 14:12:09 +00:00
|
|
|
|
2017-04-24 19:21:18 +00:00
|
|
|
end Behavorial;
|