├── FPGA ├── work │ └── .gitignore ├── iseconfig │ └── .gitignore ├── config.vhd ├── dvid_in │ ├── dvid_gearbox.vhd │ ├── tmds_decode.vhd │ ├── serialiser_in.vhd │ ├── dvid_input_channel.vhd │ └── dvid_in.vhd ├── memory.vhd ├── constraints │ └── miniSpartan6.ucf ├── display.vhd ├── dvid_out │ ├── dvid_out_clocking.vhd │ ├── tmds_encoder.vhd │ ├── output_serialiser.vhd │ └── dvid_out.vhd ├── fpga_matrix.vhd ├── ledctrl.vhd └── fpga_matrix.xise └── README.md /FPGA/work/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /FPGA/iseconfig/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fpga-led-matrix 2 | HDMI decoder and LED matrix controller. 3 | 4 | 5 | Hardware 6 | ======== 7 | 8 | * [miniSpartan6+](http://www.scarabhardware.com/minispartan6/). 9 | * [32x32 LED matrix panels](https://www.sparkfun.com/products/12584). 10 | * RaspberryPi B+ for generating the HDMI signal. 11 | 12 | Wiring: 13 | 14 | | FPGA | LED matrix | 15 | |--- |--- | 16 | | A0 | R0 | 17 | | A1 | R1 | 18 | | A2 | G0 | 19 | | A3 | G1 | 20 | | A4 | B0 | 21 | | A5 | B1 | 22 | | A6 | A | 23 | | A7 | B | 24 | | A8 | C | 25 | | A9 | D | 26 | | A10 | N/C | 27 | | A11 | N/C | 28 | | B0 | CLK | 29 | | B1 | STB | 30 | | B2 | OE | 31 | | GND | GND | 32 | 33 | HDMI input signal should be VGA (640x480) @ 60Hz. 34 | 35 | 36 | References 37 | ========== 38 | 39 | HDMI in/out code from [hamsterworks.co.nz](http://hamsterworks.co.nz/mediawiki/index.php/MiniSpartan6%2B_DVID_Logo). 40 | 41 | LED matrix controller inspired by [Adafruit's version](https://github.com/adafruit/rgbmatrix-fpga). 42 | -------------------------------------------------------------------------------- /FPGA/config.vhd: -------------------------------------------------------------------------------- 1 | -- Adafruit RGB LED Matrix Display Driver 2 | -- User-editable configuration and constants package 3 | -- 4 | -- Copyright (c) 2012 Brian Nezvadovitz 5 | -- This software is distributed under the terms of the MIT License shown below. 6 | -- 7 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 8 | -- of this software and associated documentation files (the "Software"), to 9 | -- deal in the Software without restriction, including without limitation the 10 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | -- sell copies of the Software, and to permit persons to whom the Software is 12 | -- furnished to do so, subject to the following conditions: 13 | -- 14 | -- The above copyright notice and this permission notice shall be included in 15 | -- all copies or substantial portions of the Software. 16 | -- 17 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | -- IN THE SOFTWARE. 24 | 25 | library ieee; 26 | use ieee.math_real.log2; 27 | use ieee.math_real.ceil; 28 | 29 | package rgbmatrix is 30 | 31 | -- User configurable constants 32 | constant NUM_PANELS : integer := 4; -- total number of LED matrix panels 33 | constant PIXEL_DEPTH : integer := 6; -- number of bits per pixel 34 | 35 | -- Special constants (change these at your own risk, stuff might break!) 36 | constant PANEL_WIDTH : integer := 32; -- width of the panel in pixels 37 | constant PANEL_HEIGHT : integer := 32; -- height of the panel in pixels 38 | constant DATA_WIDTH : positive := PIXEL_DEPTH * 3; -- one bit for each subpixel (3) 39 | 40 | -- Derived constants 41 | constant IMG_WIDTH : positive := PANEL_WIDTH * NUM_PANELS; 42 | constant IMG_HEIGHT : positive := PANEL_HEIGHT; 43 | constant IMG_WIDTH_LOG2 : positive := positive(log2(real(IMG_WIDTH))); 44 | constant ADDR_WIDTH : positive := positive(log2(real(IMG_WIDTH * IMG_HEIGHT))); 45 | 46 | end rgbmatrix; -------------------------------------------------------------------------------- /FPGA/dvid_in/dvid_gearbox.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- 4 | -- Module Name: Gearbox - Behavioral 5 | -- Project Name: DVI-I Input 6 | -- Description: Receives the 5-bits-per-cycle data from the serialisers at twice 7 | -- the pixel clock, then 'downshifts' the data to 10-bit words. 8 | -- 9 | -- The 'framing' signal allows to bit-slip to different word 10 | -- framing, allowing the design to hunt for the sync codewords. 11 | -- 12 | -- Revision: 13 | -- Revision 0.01 - File Created 14 | -- Additional Comments: 15 | -- 16 | ---------------------------------------------------------------------------------- 17 | library IEEE; 18 | use IEEE.STD_LOGIC_1164.ALL; 19 | 20 | entity gearbox is 21 | Port ( clk_fabric_x2 : in STD_LOGIC; 22 | invert : in STD_LOGIC; 23 | framing : in std_logic_vector(3 downto 0); 24 | data_in : in std_logic_vector(4 downto 0); 25 | data_out : out std_logic_vector(9 downto 0)); 26 | end gearbox; 27 | 28 | architecture Behavioral of gearbox is 29 | signal every_other : std_logic := '0'; 30 | signal joined : std_logic_vector(14 downto 0); 31 | begin 32 | 33 | process(clk_fabric_x2) 34 | begin 35 | if rising_edge(clk_fabric_x2) then 36 | if every_other = '1' then 37 | case framing is 38 | when "0000" => data_out <= joined( 9 downto 0); 39 | when "0001" => data_out <= joined(10 downto 1); 40 | when "0010" => data_out <= joined(11 downto 2); 41 | when "0011" => data_out <= joined(12 downto 3); 42 | when "0100" => data_out <= joined(13 downto 4); 43 | when others => NULL; 44 | end case; 45 | else 46 | case framing is 47 | when "0101" => data_out <= joined( 9 downto 0); 48 | when "0110" => data_out <= joined(10 downto 1); 49 | when "0111" => data_out <= joined(11 downto 2); 50 | when "1000" => data_out <= joined(12 downto 3); 51 | when "1001" => data_out <= joined(13 downto 4); 52 | when others => NULL; 53 | end case; 54 | end if; 55 | if invert = '1' then 56 | joined <= data_in & joined(joined'high downto 5) ; 57 | else 58 | joined <= (data_in xor "11111") & joined(joined'high downto 5) ; 59 | end if; 60 | every_other <= not every_other; 61 | end if; 62 | end process; 63 | 64 | end Behavioral; 65 | 66 | -------------------------------------------------------------------------------- /FPGA/memory.vhd: -------------------------------------------------------------------------------- 1 | -- Adafruit RGB LED Matrix Display Driver 2 | -- Special memory for the framebuffer with separate read/write clocks 3 | -- 4 | -- Copyright (c) 2012 Brian Nezvadovitz 5 | -- This software is distributed under the terms of the MIT License shown below. 6 | -- 7 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 8 | -- of this software and associated documentation files (the "Software"), to 9 | -- deal in the Software without restriction, including without limitation the 10 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | -- sell copies of the Software, and to permit persons to whom the Software is 12 | -- furnished to do so, subject to the following conditions: 13 | -- 14 | -- The above copyright notice and this permission notice shall be included in 15 | -- all copies or substantial portions of the Software. 16 | -- 17 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | -- IN THE SOFTWARE. 24 | 25 | -- For more information on how to infer RAMs on Altera devices see this page: 26 | -- http://quartushelp.altera.com/current/mergedProjects/hdl/vhdl/vhdl_pro_ram_inferred.htm 27 | 28 | library ieee; 29 | use ieee.std_logic_1164.all; 30 | use ieee.numeric_std.all; 31 | use ieee.std_logic_unsigned.all; 32 | 33 | use work.rgbmatrix.all; 34 | 35 | entity memory is 36 | port ( 37 | wr_clk : in std_logic; 38 | wr_enable : in std_logic; 39 | wr_addr : in std_logic_vector(ADDR_WIDTH - 1 downto 0); 40 | wr_data : in std_logic_vector(DATA_WIDTH - 1 downto 0); 41 | 42 | rd_clk : in std_logic; 43 | rd_addr : in std_logic_vector(ADDR_WIDTH - 2 downto 0); 44 | rd_data : out std_logic_vector(DATA_WIDTH * 2 - 1 downto 0) 45 | ); 46 | end memory; 47 | 48 | architecture bhv of memory is 49 | -- Inferred RAM storage signal 50 | type ram is array(2 ** ADDR_WIDTH - 1 downto 0) of std_logic_vector(DATA_WIDTH - 1 downto 0); 51 | signal ram_block : ram; 52 | begin 53 | 54 | -- Write process for the memory 55 | process(wr_clk, wr_enable, wr_data) 56 | begin 57 | if (rising_edge(wr_clk) and wr_enable = '1') then 58 | ram_block(conv_integer(wr_addr)) <= wr_data; 59 | end if; 60 | end process; 61 | 62 | -- Read process for the memory 63 | process(rd_clk, rd_addr) 64 | variable rd_data_up : std_logic_vector(DATA_WIDTH - 1 downto 0); 65 | variable rd_data_low : std_logic_vector(DATA_WIDTH - 1 downto 0); 66 | begin 67 | if (rising_edge(rd_clk)) then 68 | rd_data_up := ram_block(conv_integer("0" & rd_addr)); 69 | rd_data_low := ram_block(conv_integer("1" & rd_addr)); 70 | rd_data <= rd_data_up & rd_data_low; 71 | end if; 72 | end process; 73 | 74 | end bhv; -------------------------------------------------------------------------------- /FPGA/constraints/miniSpartan6.ucf: -------------------------------------------------------------------------------- 1 | # Constraints for fpga_matrix project 2 | 3 | VCCAUX = 3.3; 4 | 5 | # LEDs 6 | NET "LEDS<0>" LOC="P11"; 7 | NET "LEDS<1>" LOC="N9"; 8 | NET "LEDS<2>" LOC="M9"; 9 | NET "LEDS<3>" LOC="P9"; 10 | NET "LEDS<4>" LOC="T8"; 11 | NET "LEDS<5>" LOC="N8"; 12 | NET "LEDS<6>" LOC="P8"; 13 | NET "LEDS<7>" LOC="P7"; 14 | 15 | # DIP switches 16 | NET switch(0) LOC = "L1" | IOSTANDARD = LVTTL | PULLUP; 17 | #NET switch(1) LOC = "L3" | IOSTANDARD = LVTTL | PULLUP; 18 | #NET switch(2) LOC = "L4" | IOSTANDARD = LVTTL | PULLUP; 19 | #NET switch(3) LOC = "L5" | IOSTANDARD = LVTTL | PULLUP; 20 | 21 | # Port A I/O Pins 22 | NET port_a(0) LOC = "E7" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 23 | NET port_a(1) LOC = "C8" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 24 | NET port_a(2) LOC = "D8" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 25 | NET port_a(3) LOC = "E8" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 26 | NET port_a(4) LOC = "D9" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 27 | NET port_a(5) LOC = "A10" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 28 | NET port_a(6) LOC = "B10" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 29 | NET port_a(7) LOC = "C10" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 30 | NET port_a(8) LOC = "E10" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 31 | NET port_a(9) LOC = "F9" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 32 | NET port_a(10) LOC = "F10" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 33 | NET port_a(11) LOC = "D11" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 34 | 35 | # Port B I/O Pins 36 | NET port_b(0) LOC = "E11" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 37 | NET port_b(1) LOC = "D14" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 38 | NET port_b(2) LOC = "D12" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 39 | NET port_b(3) LOC = "E12" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 40 | NET port_b(4) LOC = "E13" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 41 | NET port_b(5) LOC = "F13" | IOSTANDARD = LVTTL | DRIVE = 2 | SLEW = SLOW; 42 | 43 | # HDMI output 44 | NET "hdmi_out_p<0>" LOC="C13" | IOSTANDARD="TMDS_33"; # IO_L63P_SCP7_0 45 | NET "hdmi_out_n<0>" LOC="A13" | IOSTANDARD="TMDS_33"; # IO_L63N_SCP6_0 46 | NET "hdmi_out_p<1>" LOC="B12" | IOSTANDARD="TMDS_33"; # IO_L62P_0 47 | NET "hdmi_out_n<1>" LOC="A12" | IOSTANDARD="TMDS_33"; # IO_L62N_VREF_0 48 | NET "hdmi_out_p<2>" LOC="C11" | IOSTANDARD="TMDS_33"; # IO_L39P_0 49 | NET "hdmi_out_n<2>" LOC="A11" | IOSTANDARD="TMDS_33"; # IO_L39N_0 50 | NET "hdmi_out_p<3>" LOC="B14" | IOSTANDARD="TMDS_33"; # IO_L65P_SCP3_0 51 | NET "hdmi_out_n<3>" LOC="A14" | IOSTANDARD="TMDS_33"; # IO_L65N_SCP2_0 52 | 53 | # HDMI input 54 | NET "hdmi_in_p<0>" LOC="C7" | IOSTANDARD="TMDS_33"; # IO_L6P_0 55 | NET "hdmi_in_n<0>" LOC="A7" | IOSTANDARD="TMDS_33"; # IO_L6N_0 56 | NET "hdmi_in_p<1>" LOC="B6" | IOSTANDARD="TMDS_33"; # IO_L4P_0 57 | NET "hdmi_in_n<1>" LOC="A6" | IOSTANDARD="TMDS_33"; # IO_L4N_0 58 | NET "hdmi_in_p<2>" LOC="B5" | IOSTANDARD="TMDS_33"; # IO_L2P_0 59 | NET "hdmi_in_n<2>" LOC="A5" | IOSTANDARD="TMDS_33"; # IO_L2N_0 60 | NET "hdmi_in_p<3>" LOC="C9" | IOSTANDARD="TMDS_33" | PERIOD=12 ns; # IO_L34P_GCLK19_0 61 | NET "hdmi_in_n<3>" LOC="A9" | IOSTANDARD="TMDS_33"; # IO_L34N_GCLK18_0 62 | NET "hdmi_in_sclk" LOC="C1" | IOSTANDARD="LVTTL"; # IO_50P_M3WE_3 63 | NET "hdmi_in_sdat" LOC="B1" | IOSTANDARD="LVTTL"; # IO_50N_M3BA2_3 -------------------------------------------------------------------------------- /FPGA/dvid_in/tmds_decode.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- 4 | -- Module Name: tmds_decode - Behavioral 5 | -- 6 | -- Description: TMDS decode as per Digital Display Working Groups Digital Visual 7 | -- Interface Revision 1.0 section 3.3.3 8 | -- 9 | -- This doesn't seem 100% correct - "elsif sometimes_inverted(8) = '0' then" should 10 | -- be "elsif sometimes_inverted(8) = '1' then" according to the standard. 11 | -- 12 | -- However it does actually work! 13 | ---------------------------------------------------------------------------------- 14 | library IEEE; 15 | use IEEE.STD_LOGIC_1164.ALL; 16 | 17 | entity tmds_decode is 18 | Port ( clk : in STD_LOGIC; 19 | data_in : in STD_LOGIC_VECTOR (9 downto 0); 20 | data_out : out STD_LOGIC_VECTOR (7 downto 0); 21 | c : out STD_LOGIC_VECTOR (1 downto 0); 22 | active_data : out std_logic); 23 | end tmds_decode; 24 | 25 | architecture Behavioral of tmds_decode is 26 | signal data_delayed : STD_LOGIC_VECTOR(9 downto 0); 27 | signal data_delayed_active : STD_LOGIC := '0'; 28 | signal data_delayed_c : STD_LOGIC_VECTOR(1 downto 0); 29 | 30 | signal sometimes_inverted : STD_LOGIC_VECTOR(8 downto 0) := (others => '0'); 31 | signal sometimes_inverted_c : STD_LOGIC_VECTOR(1 downto 0) := (others => '0'); 32 | signal sometimes_inverted_active : STD_LOGIC := '0'; 33 | begin 34 | 35 | process(clk) 36 | begin 37 | if rising_edge(clk) then 38 | -- Final stage in the pipeline 39 | if sometimes_inverted_active = '0' then 40 | c <= sometimes_inverted_c; 41 | active_data <= '0'; 42 | data_out <= (others => '0'); 43 | elsif sometimes_inverted(8) = '0' then 44 | c <= sometimes_inverted_c; 45 | active_data <= '1'; 46 | data_out(0) <= sometimes_inverted(0); 47 | data_out(1) <= sometimes_inverted(1) XOR sometimes_inverted(0); 48 | data_out(2) <= sometimes_inverted(2) XOR sometimes_inverted(1); 49 | data_out(3) <= sometimes_inverted(3) XOR sometimes_inverted(2); 50 | data_out(4) <= sometimes_inverted(4) XOR sometimes_inverted(3); 51 | data_out(5) <= sometimes_inverted(5) XOR sometimes_inverted(4); 52 | data_out(6) <= sometimes_inverted(6) XOR sometimes_inverted(5); 53 | data_out(7) <= sometimes_inverted(7) XOR sometimes_inverted(6); 54 | else 55 | c <= sometimes_inverted_c; 56 | active_data <= '1'; 57 | data_out(0) <= sometimes_inverted(0); 58 | data_out(1) <= sometimes_inverted(1) XNOR sometimes_inverted(0); 59 | data_out(2) <= sometimes_inverted(2) XNOR sometimes_inverted(1); 60 | data_out(3) <= sometimes_inverted(3) XNOR sometimes_inverted(2); 61 | data_out(4) <= sometimes_inverted(4) XNOR sometimes_inverted(3); 62 | data_out(5) <= sometimes_inverted(5) XNOR sometimes_inverted(4); 63 | data_out(6) <= sometimes_inverted(6) XNOR sometimes_inverted(5); 64 | data_out(7) <= sometimes_inverted(7) XNOR sometimes_inverted(6); 65 | end if; 66 | 67 | sometimes_inverted_active <= data_delayed_active; 68 | sometimes_inverted_c <= data_delayed_c; 69 | if data_delayed(9) = '1' then 70 | sometimes_inverted <= data_delayed(8 downto 0) xor "011111111"; 71 | else 72 | sometimes_inverted <= data_delayed(8 downto 0); 73 | end if; 74 | 75 | --- first step in the pipeline 76 | case data_in is 77 | when "0010101011" => data_delayed_c <= "01"; data_delayed_active <= '0'; 78 | when "1101010100" => data_delayed_c <= "00"; data_delayed_active <= '0'; 79 | when "0101010100" => data_delayed_c <= "10"; data_delayed_active <= '0'; 80 | when "1010101011" => data_delayed_c <= "11"; data_delayed_active <= '0'; 81 | when others => data_delayed_c <= "00"; data_delayed_active <= '1'; 82 | end case; 83 | 84 | data_delayed <= data_in; 85 | end if; 86 | end process; 87 | 88 | end Behavioral; 89 | 90 | -------------------------------------------------------------------------------- /FPGA/display.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Company: 3 | -- Engineer: 4 | -- 5 | -- Create Date: 23:37:20 01/25/2015 6 | -- Design Name: 7 | -- Module Name: display - Behavioral 8 | -- Project Name: 9 | -- Target Devices: 10 | -- Tool versions: 11 | -- Description: 12 | -- 13 | -- Dependencies: 14 | -- 15 | -- Revision: 16 | -- Revision 0.01 - File Created 17 | -- Additional Comments: 18 | -- 19 | ---------------------------------------------------------------------------------- 20 | library IEEE; 21 | use IEEE.STD_LOGIC_1164.ALL; 22 | use IEEE.NUMERIC_STD.ALL; 23 | 24 | use work.rgbmatrix.all; 25 | 26 | entity display is 27 | Port ( 28 | clk_pixel : IN std_logic; 29 | 30 | i_red : IN std_logic_vector(7 downto 0); 31 | i_green : IN std_logic_vector(7 downto 0); 32 | i_blue : IN std_logic_vector(7 downto 0); 33 | i_blank : IN std_logic; 34 | i_hsync : IN std_logic; 35 | i_vsync : IN std_logic; 36 | 37 | o_red : OUT std_logic_vector(7 downto 0); 38 | o_green : OUT std_logic_vector(7 downto 0); 39 | o_blue : OUT std_logic_vector(7 downto 0); 40 | o_blank : OUT std_logic; 41 | o_hsync : OUT std_logic; 42 | o_vsync : OUT std_logic; 43 | 44 | wr_enable : OUT std_logic; 45 | wr_addr : OUT std_logic_vector(ADDR_WIDTH - 1 downto 0); 46 | wr_data : OUT std_logic_vector(DATA_WIDTH - 1 downto 0) 47 | ); 48 | end display; 49 | 50 | architecture Behavioral of display is 51 | 52 | ------------------------- 53 | -- Part of the pipeline 54 | ------------------------- 55 | signal a_red : std_logic_vector(7 downto 0); 56 | signal a_green : std_logic_vector(7 downto 0); 57 | signal a_blue : std_logic_vector(7 downto 0); 58 | signal a_blank : std_logic; 59 | signal a_hsync : std_logic; 60 | signal a_vsync : std_logic; 61 | 62 | ------------------------------- 63 | -- Counters for screen position 64 | ------------------------------- 65 | signal x : std_logic_vector(10 downto 0); 66 | signal y : std_logic_vector(10 downto 0); 67 | 68 | signal addr : std_logic_vector(ADDR_WIDTH - 1 downto 0); 69 | 70 | begin 71 | 72 | -- Address for 128x32 display 73 | addr <= y(4 downto 0) & x(6 downto 0); 74 | 75 | process(clk_pixel) 76 | variable m_red, m_green, m_blue : std_logic_vector(PIXEL_DEPTH - 1 downto 0); 77 | variable data : std_logic_vector(DATA_WIDTH - 1 downto 0); 78 | begin 79 | if rising_edge(clk_pixel) then 80 | wr_enable <= '0'; 81 | 82 | if a_blank = '0' and unsigned(x) < IMG_WIDTH and unsigned(y) < IMG_HEIGHT then 83 | m_red := a_red(a_red'high downto a_red'high - PIXEL_DEPTH + 1); 84 | m_green := a_green(a_green'high downto a_green'high - PIXEL_DEPTH + 1); 85 | m_blue := a_blue(a_blue'high downto a_blue'high - PIXEL_DEPTH + 1); 86 | 87 | data := m_red & m_green & m_blue; 88 | 89 | wr_enable <= '1'; 90 | wr_addr <= addr; 91 | wr_data <= data; 92 | end if; 93 | 94 | o_red <= a_red; 95 | o_green <= a_green; 96 | o_blue <= a_blue; 97 | o_blank <= a_blank; 98 | o_hsync <= a_hsync; 99 | o_vsync <= a_vsync; 100 | 101 | a_red <= i_red; 102 | a_green <= i_green; 103 | a_blue <= i_blue; 104 | a_blank <= i_blank; 105 | a_hsync <= i_hsync; 106 | a_vsync <= i_vsync; 107 | 108 | -- Working out where we are in the screen.. 109 | if i_blank = '1' and i_vsync /= a_vsync then 110 | y <= (others => '0'); 111 | end if; 112 | 113 | if i_blank = '0' then 114 | x <= std_logic_vector(unsigned(x) + 1); 115 | end if; 116 | 117 | -- Start of the blanking interval? 118 | if a_blank = '0' and i_blank = '1' then 119 | y <= std_logic_vector(unsigned(y) + 1); 120 | x <= (others => '1'); 121 | end if; 122 | end if; 123 | end process; 124 | 125 | end Behavioral; 126 | 127 | -------------------------------------------------------------------------------- /FPGA/dvid_out/dvid_out_clocking.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 20, 9 | -- CLKOUT0_DIVIDE => 2, CLKOUT0_PHASE => 0.0, -- Output 10x original frequency 10 | -- CLKOUT1_DIVIDE => 10, CLKOUT1_PHASE => 0.0, -- Output 2x original frequency 11 | -- CLKOUT2_DIVIDE => 20, CLKOUT2_PHASE => 0.0, -- Output 1x original frequency 12 | -- CLKIN_PERIOD => 20.0, 13 | -- 14 | -- For pixel rates between 40Mhz and 100MHz use the following PLL settings: 15 | -- CLKFBOUT_MULT => 10, 16 | -- CLKOUT0_DIVIDE => 1, CLKOUT0_PHASE => 0.0, -- Output 10x original frequency 17 | -- CLKOUT1_DIVIDE => 5, CLKOUT1_PHASE => 0.0, -- Output 2x original frequency 18 | -- CLKOUT2_DIVIDE => 10, CLKOUT2_PHASE => 0.0, -- Output 1x original frequency 19 | -- CLKIN_PERIOD => 10.0, 20 | ---------------------------------------------------------------------------------- 21 | library IEEE; 22 | use IEEE.STD_LOGIC_1164.ALL; 23 | library UNISIM; 24 | use UNISIM.VComponents.all; 25 | 26 | entity dvid_out_clocking is 27 | Port ( clk_pixel : in STD_LOGIC; 28 | clk_x1 : out STD_LOGIC; 29 | clk_x2 : out STD_LOGIC; 30 | clk_x10 : out STD_LOGIC; 31 | serdes_strobe : out STD_LOGIC); 32 | end dvid_out_clocking; 33 | 34 | architecture Behavioral of dvid_out_clocking is 35 | signal clock_local_x1 : std_logic; 36 | signal clock_local_x2 : std_logic; 37 | signal clock_local_x10 : std_logic; 38 | signal clock_x10_unbuffered : std_logic; 39 | signal clock_x2_unbuffered : std_logic; 40 | signal clock_x1_unbuffered : std_logic; 41 | signal clk_feedback : std_logic; 42 | signal clk50_buffered : std_logic; 43 | signal pll_locked : std_logic; 44 | begin 45 | clk_x1 <= clock_local_x1; 46 | clk_x2 <= clock_local_x2; 47 | clk_x10 <= clock_local_x10; 48 | 49 | -- Multiply clk50m by 10, then : 50 | -- * divide by 1 for the bit clock (pixel clock x10) 51 | -- * divide by 5 for the pixel clock x2 52 | -- * divide by 10 for the pixel clock 53 | -- Because the all come from the same PLL the will all be in phase 54 | PLL_BASE_inst : PLL_BASE 55 | generic map ( 56 | CLKFBOUT_MULT => 10, 57 | CLKOUT0_DIVIDE => 1, CLKOUT0_PHASE => 0.0, -- Output 10x original frequency 58 | CLKOUT1_DIVIDE => 5, CLKOUT1_PHASE => 0.0, -- Output 2x original frequency 59 | CLKOUT2_DIVIDE => 10, CLKOUT2_PHASE => 0.0, -- Output 1x original frequency 60 | CLK_FEEDBACK => "CLKFBOUT", 61 | CLKIN_PERIOD => 10.0, 62 | DIVCLK_DIVIDE => 1 63 | ) 64 | port map ( 65 | CLKFBOUT => clk_feedback, 66 | CLKOUT0 => clock_x10_unbuffered, 67 | CLKOUT1 => clock_x2_unbuffered, 68 | CLKOUT2 => clock_x1_unbuffered, 69 | CLKOUT3 => open, 70 | CLKOUT4 => open, 71 | CLKOUT5 => open, 72 | LOCKED => pll_locked, 73 | CLKFBIN => clk_feedback, 74 | CLKIN => clk_pixel, 75 | RST => '0' 76 | ); 77 | 78 | BUFG_pclockx2 : BUFG port map ( I => clock_x2_unbuffered, O => clock_local_x2); 79 | BUFG_pclock : BUFG port map ( I => clock_x1_unbuffered, O => clock_local_x1); 80 | 81 | 82 | BUFPLL_inst : BUFPLL 83 | generic map ( 84 | DIVIDE => 5, -- DIVCLK divider (1-8) !!!! IMPORTANT TO CHANGE THIS AS NEEDED !!!! 85 | ENABLE_SYNC => TRUE -- Enable synchrnonization between PLL and GCLK (TRUE/FALSE) -- should be true 86 | ) 87 | port map ( 88 | IOCLK => clock_local_x10, -- Clock used to send bits 89 | LOCK => open, 90 | SERDESSTROBE => serdes_strobe, -- Clock use to load data into SERDES 91 | GCLK => clock_local_x2, -- Global clock use as a reference for serdes_strobe 92 | LOCKED => pll_locked, -- When the upstream PLL is locked 93 | PLLIN => clock_x10_unbuffered -- What clock to use - this must be unbuffered 94 | ); 95 | end Behavioral; -------------------------------------------------------------------------------- /FPGA/dvid_out/tmds_encoder.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- 4 | -- Description: TMDS Encoder 5 | -- 8 bits colour, 2 control bits and one blanking bits in 6 | -- 10 bits of TMDS encoded data out 7 | -- Clocked at the pixel clock 8 | -- 9 | ---------------------------------------------------------------------------------- 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | use IEEE.STD_LOGIC_UNSIGNED.ALL; 13 | 14 | entity TMDS_encoder is 15 | Port ( clk : in STD_LOGIC; 16 | data : in STD_LOGIC_VECTOR (7 downto 0); 17 | c : in STD_LOGIC_VECTOR (1 downto 0); 18 | blank : in STD_LOGIC; 19 | encoded : out STD_LOGIC_VECTOR (9 downto 0)); 20 | end TMDS_encoder; 21 | 22 | architecture Behavioral of TMDS_encoder is 23 | signal xored : STD_LOGIC_VECTOR (8 downto 0); 24 | signal xnored : STD_LOGIC_VECTOR (8 downto 0); 25 | 26 | signal ones : STD_LOGIC_VECTOR (3 downto 0); 27 | signal data_word : STD_LOGIC_VECTOR (8 downto 0); 28 | signal data_word_inv : STD_LOGIC_VECTOR (8 downto 0); 29 | signal data_word_disparity : STD_LOGIC_VECTOR (3 downto 0); 30 | signal dc_bias : STD_LOGIC_VECTOR (3 downto 0) := (others => '0'); 31 | begin 32 | -- Work our the two different encodings for the byte 33 | xored(0) <= data(0); 34 | xored(1) <= data(1) xor xored(0); 35 | xored(2) <= data(2) xor xored(1); 36 | xored(3) <= data(3) xor xored(2); 37 | xored(4) <= data(4) xor xored(3); 38 | xored(5) <= data(5) xor xored(4); 39 | xored(6) <= data(6) xor xored(5); 40 | xored(7) <= data(7) xor xored(6); 41 | xored(8) <= '1'; 42 | 43 | xnored(0) <= data(0); 44 | xnored(1) <= data(1) xnor xnored(0); 45 | xnored(2) <= data(2) xnor xnored(1); 46 | xnored(3) <= data(3) xnor xnored(2); 47 | xnored(4) <= data(4) xnor xnored(3); 48 | xnored(5) <= data(5) xnor xnored(4); 49 | xnored(6) <= data(6) xnor xnored(5); 50 | xnored(7) <= data(7) xnor xnored(6); 51 | xnored(8) <= '0'; 52 | 53 | -- Count how many ones are set in data 54 | ones <= "0000" + data(0) + data(1) + data(2) + data(3) 55 | + data(4) + data(5) + data(6) + data(7); 56 | 57 | -- Decide which encoding to use 58 | process(ones, data(0), xnored, xored) 59 | begin 60 | if ones > 4 or (ones = 4 and data(0) = '0') then 61 | data_word <= xnored; 62 | data_word_inv <= NOT(xnored); 63 | else 64 | data_word <= xored; 65 | data_word_inv <= NOT(xored); 66 | end if; 67 | end process; 68 | 69 | -- Work out the DC bias of the dataword; 70 | data_word_disparity <= "1100" + data_word(0) + data_word(1) + data_word(2) + data_word(3) 71 | + data_word(4) + data_word(5) + data_word(6) + data_word(7); 72 | 73 | -- Now work out what the output should be 74 | process(clk) 75 | begin 76 | if rising_edge(clk) then 77 | if blank = '1' then 78 | -- In the control periods, all values have and have balanced bit count 79 | case c is 80 | when "00" => encoded <= "1101010100"; 81 | when "01" => encoded <= "0010101011"; 82 | when "10" => encoded <= "0101010100"; 83 | when others => encoded <= "1010101011"; 84 | end case; 85 | dc_bias <= (others => '0'); 86 | else 87 | if dc_bias = "00000" or data_word_disparity = 0 then 88 | -- dataword has no disparity 89 | if data_word(8) = '1' then 90 | encoded <= "01" & data_word(7 downto 0); 91 | dc_bias <= dc_bias + data_word_disparity; 92 | else 93 | encoded <= "10" & data_word_inv(7 downto 0); 94 | dc_bias <= dc_bias - data_word_disparity; 95 | end if; 96 | elsif (dc_bias(3) = '0' and data_word_disparity(3) = '0') or 97 | (dc_bias(3) = '1' and data_word_disparity(3) = '1') then 98 | encoded <= '1' & data_word(8) & data_word_inv(7 downto 0); 99 | dc_bias <= dc_bias + data_word(8) - data_word_disparity; 100 | else 101 | encoded <= '0' & data_word; 102 | dc_bias <= dc_bias - data_word_inv(8) + data_word_disparity; 103 | end if; 104 | end if; 105 | end if; 106 | end process; 107 | end Behavioral; -------------------------------------------------------------------------------- /FPGA/dvid_in/serialiser_in.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- 4 | -- Module Name: input_serialiser 5 | -- 6 | -- Description: A 5-bits per cycle SDR input serialiser 7 | -- 8 | -- Maybe in the future the 'bitslip' funciton can be implemented. 9 | ---------------------------------------------------------------------------------- 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | library UNISIM; 13 | use UNISIM.VComponents.all; 14 | 15 | entity input_serialiser is 16 | Port ( clk_fabric_x2 : in STD_LOGIC; 17 | clk_input : in STD_LOGIC; 18 | strobe : in STD_LOGIC; 19 | ser_data : out STD_LOGIC_VECTOR (4 downto 0); 20 | ser_input : in STD_LOGIC); 21 | end input_serialiser; 22 | 23 | architecture Behavioral of input_serialiser is 24 | signal clk0, clk1, clkdiv : std_logic; 25 | signal cascade : std_logic; 26 | constant bitslip : std_logic := '0'; 27 | begin 28 | clkdiv <= clk_fabric_x2; 29 | clk0 <= clk_input; 30 | clk1 <= '0'; 31 | 32 | ISERDES2_master : ISERDES2 33 | generic map ( 34 | BITSLIP_ENABLE => TRUE, -- Enable Bitslip Functionality (TRUE/FALSE) 35 | DATA_RATE => "SDR", -- Data-rate ("SDR" or "DDR") 36 | DATA_WIDTH => 5, -- Parallel data width selection (2-8) 37 | INTERFACE_TYPE => "RETIMED", -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 38 | SERDES_MODE => "MASTER" -- "NONE", "MASTER" or "SLAVE" 39 | ) 40 | port map ( 41 | CFB0 => open, -- 1-bit output: Clock feed-through route output 42 | CFB1 => open, -- 1-bit output: Clock feed-through route output 43 | DFB => open, -- 1-bit output: Feed-through clock output 44 | FABRICOUT => open, -- 1-bit output: Unsynchrnonized data output 45 | INCDEC => open, -- 1-bit output: Phase detector output 46 | -- Q1 - Q4: 1-bit (each) output: Registered outputs to FPGA logic 47 | Q1 => ser_data(1), 48 | Q2 => ser_data(2), 49 | Q3 => ser_data(3), 50 | Q4 => ser_data(4), 51 | SHIFTOUT => cascade, -- 1-bit output: Cascade output signal for master/slave I/O 52 | VALID => open, -- 1-bit output: Output status of the phase detector 53 | BITSLIP => bitslip , -- 1-bit input: Bitslip enable input 54 | CE0 => '1', -- 1-bit input: Clock enable input 55 | CLK0 => clk0, -- 1-bit input: I/O clock network input 56 | CLK1 => clk1, -- 1-bit input: Secondary I/O clock network input 57 | CLKDIV => clkdiv, -- 1-bit input: FPGA logic domain clock input 58 | D => ser_input, -- 1-bit input: Input data 59 | IOCE => strobe, -- 1-bit input: Data strobe input 60 | RST => '0', -- 1-bit input: Asynchronous reset input 61 | SHIFTIN => '0' -- 1-bit input: Cascade input signal for master/slave I/O 62 | ); 63 | 64 | ISERDES2_slave : ISERDES2 65 | generic map ( 66 | BITSLIP_ENABLE => TRUE, -- Enable Bitslip Functionality (TRUE/FALSE) 67 | DATA_RATE => "SDR", -- Data-rate ("SDR" or "DDR") 68 | DATA_WIDTH => 5, -- Parallel data width selection (2-8) 69 | INTERFACE_TYPE => "RETIMED", -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 70 | SERDES_MODE => "SLAVE" -- "NONE", "MASTER" or "SLAVE" 71 | ) 72 | port map ( 73 | CFB0 => open, -- 1-bit output: Clock feed-through route output 74 | CFB1 => open, -- 1-bit output: Clock feed-through route output 75 | DFB => open, -- 1-bit output: Feed-through clock output 76 | FABRICOUT => open, -- 1-bit output: Unsynchrnonized data output 77 | INCDEC => open, -- 1-bit output: Phase detector output 78 | -- Q1 - Q4: 1-bit (each) output: Registered outputs to FPGA logic 79 | Q1 => open, 80 | Q2 => open, 81 | Q3 => open, 82 | Q4 => ser_data(0), 83 | SHIFTOUT => open, -- 1-bit output: Cascade output signal for master/slave I/O 84 | VALID => open, -- 1-bit output: Output status of the phase detector 85 | BITSLIP => bitslip, -- 1-bit input: Bitslip enable input 86 | CE0 => '1', -- 1-bit input: Clock enable input 87 | CLK0 => clk0, -- 1-bit input: I/O clock network input 88 | CLK1 => clk1, -- 1-bit input: Secondary I/O clock network input 89 | CLKDIV => clkdiv, -- 1-bit input: FPGA logic domain clock input 90 | D => '0', -- 1-bit input: Input data 91 | IOCE => '1', -- 1-bit input: Data strobe input 92 | RST => '0', -- 1-bit input: Asynchronous reset input 93 | SHIFTIN => cascade -- 1-bit input: Cascade input signal for master/slave I/O 94 | ); 95 | 96 | end Behavioral; 97 | 98 | -------------------------------------------------------------------------------- /FPGA/dvid_in/dvid_input_channel.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- 4 | -- Module Name: input_channel - Behavioral 5 | -- Description: The end-to-end processing of a TMDS input channel 6 | -- 7 | ---------------------------------------------------------------------------------- 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | library UNISIM; 11 | use UNISIM.VComponents.all; 12 | 13 | 14 | entity input_channel is 15 | GENERIC( 16 | fixed_delay : in natural 17 | ); 18 | Port ( clk_fabric : in STD_LOGIC; 19 | clk_fabric_x2 : in STD_LOGIC; 20 | clk_input : in STD_LOGIC; 21 | strobe : in STD_LOGIC; 22 | tmds_p : in STD_LOGIC; 23 | tmds_n : in STD_LOGIC; 24 | invert : in STD_LOGIC; 25 | framing : in std_logic_vector(3 downto 0); 26 | data_out : out STD_LOGIC_VECTOR (7 downto 0); 27 | control : out STD_LOGIC_VECTOR (1 downto 0); 28 | active_data : out std_logic; 29 | sync_seen : out std_logic; 30 | 31 | adjust_delay : IN std_logic; 32 | increase_delay : IN std_logic; 33 | reset_delay : IN std_logic; 34 | start_calibrate : IN std_logic; 35 | calibrate_busy : OUT std_logic 36 | ); 37 | end input_channel; 38 | 39 | architecture Behavioral of input_channel is 40 | 41 | COMPONENT input_delay 42 | GENERIC( 43 | fixed_delay : in natural 44 | ); 45 | PORT( 46 | bit_clock : IN std_logic; 47 | data_in : IN std_logic; 48 | data_out : OUT std_logic; 49 | 50 | control_clock : IN std_logic; 51 | adjust_delay : IN std_logic; 52 | increase_delay : IN std_logic; 53 | reset_delay : IN std_logic; 54 | start_calibrate : IN std_logic; 55 | calibrate_busy : OUT std_logic 56 | ); 57 | END COMPONENT; 58 | 59 | COMPONENT input_serialiser 60 | PORT( 61 | clk_fabric_x2 : IN std_logic; 62 | clk_input : IN std_logic; 63 | strobe : IN std_logic; 64 | ser_input : IN std_logic; 65 | ser_data : OUT std_logic_vector(4 downto 0) 66 | ); 67 | END COMPONENT; 68 | 69 | COMPONENT gearbox 70 | PORT( 71 | clk_fabric_x2 : IN std_logic; 72 | framing : IN std_logic_vector(3 downto 0); 73 | invert : IN std_logic; 74 | data_in : IN std_logic_vector(4 downto 0); 75 | data_out : OUT std_logic_vector(9 downto 0) 76 | ); 77 | END COMPONENT; 78 | 79 | COMPONENT tmds_decode 80 | PORT( 81 | clk : IN std_logic; 82 | data_in : IN std_logic_vector(9 downto 0); 83 | data_out : OUT std_logic_vector(7 downto 0); 84 | c : OUT std_logic_vector(1 downto 0); 85 | active_data : OUT std_logic 86 | ); 87 | END COMPONENT; 88 | 89 | signal serial_data : std_logic; 90 | signal delayed_serial_data : std_logic; 91 | signal raw_tmds_word : std_logic_vector(9 downto 0); 92 | signal half_words : std_logic_vector(4 downto 0); 93 | begin 94 | 95 | diff_input : IBUFDS 96 | generic map ( 97 | DIFF_TERM => FALSE, 98 | IBUF_LOW_PWR => TRUE, 99 | IOSTANDARD => "TMDS_33") 100 | port map ( 101 | O => serial_data, 102 | I => tmds_p, 103 | IB => tmds_n 104 | ); 105 | 106 | --i_input_delay: input_delay GENERIC MAP( 107 | -- fixed_delay => fixed_delay 108 | -- ) PORT MAP( 109 | -- bit_clock => clk_input, 110 | -- data_in => serial_data, 111 | -- data_out => delayed_serial_data, 112 | -- control_clock => clk_fabric_x2, 113 | -- adjust_delay => adjust_delay, 114 | -- increase_delay => increase_delay, 115 | -- reset_delay => reset_delay, 116 | -- start_calibrate => start_calibrate, 117 | -- calibrate_busy => calibrate_busy 118 | -- ); 119 | 120 | i_input_serialiser: input_serialiser PORT MAP( 121 | clk_fabric_x2 => clk_fabric_x2, 122 | clk_input => clk_input, 123 | strobe => strobe, 124 | -- ser_input => delayed_serial_data, 125 | ser_input => serial_data, 126 | ser_data => half_words 127 | ); 128 | 129 | i_gearbox: gearbox PORT MAP( 130 | clk_fabric_x2 => clk_fabric_x2, 131 | invert => invert, 132 | framing => framing, 133 | data_in => half_words, 134 | data_out => raw_tmds_word 135 | ); 136 | 137 | i_tmds_decode: tmds_decode PORT MAP( 138 | clk => clk_fabric, 139 | data_in => raw_tmds_word, 140 | data_out => data_out, 141 | c => control, 142 | active_data => active_data 143 | ); 144 | 145 | look_for_sync: process (clk_fabric) 146 | begin 147 | if rising_edge(clk_fabric) then 148 | ------------------------------------------------------------ 149 | -- Is the TMDS data one of two special sync codewords? 150 | ------------------------------------------------------------ 151 | if raw_tmds_word = "1101010100" or raw_tmds_word = "0010101011" then 152 | sync_seen <= '1'; 153 | else 154 | sync_seen <= '0'; 155 | end if; 156 | end if; 157 | end process; 158 | end Behavioral; 159 | 160 | -------------------------------------------------------------------------------- /FPGA/dvid_out/output_serialiser.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- 4 | -- Module Name: output_serialiser - Behavioral 5 | -- Description: A 5-bit SDR output serialiser 6 | ---------------------------------------------------------------------------------- 7 | library IEEE; 8 | use IEEE.STD_LOGIC_1164.ALL; 9 | library UNISIM; 10 | use UNISIM.VComponents.all; 11 | 12 | entity output_serialiser is 13 | Port ( clk_load : in STD_LOGIC; 14 | clk_output : in STD_LOGIC; 15 | strobe : in STD_LOGIC; 16 | ser_data : in STD_LOGIC_VECTOR (4 downto 0); 17 | ser_output : out STD_LOGIC); 18 | end output_serialiser; 19 | 20 | architecture Behavioral of output_serialiser is 21 | signal clk0, clk1, clkdiv : std_logic; 22 | signal cascade1, cascade2, cascade3, cascade4 : std_logic; 23 | begin 24 | clkdiv <= clk_load; 25 | clk0 <= clk_output; 26 | clk1 <= '0'; 27 | 28 | OSERDES2_master : OSERDES2 29 | generic map ( 30 | BYPASS_GCLK_FF => FALSE, -- Bypass CLKDIV syncronization registers (TRUE/FALSE) 31 | DATA_RATE_OQ => "SDR", -- Output Data Rate ("SDR" or "DDR") 32 | DATA_RATE_OT => "SDR", -- 3-state Data Rate ("SDR" or "DDR") 33 | DATA_WIDTH => 5, -- Parallel data width (2-8) 34 | OUTPUT_MODE => "SINGLE_ENDED", -- "SINGLE_ENDED" or "DIFFERENTIAL" 35 | SERDES_MODE => "MASTER", -- "NONE", "MASTER" or "SLAVE" 36 | TRAIN_PATTERN => 0 -- Training Pattern (0-15) 37 | ) port map ( 38 | OQ => ser_output, -- 1-bit output: Data output to pad or IODELAY2 39 | SHIFTOUT1 => cascade1, -- 1-bit output: Cascade data output 40 | SHIFTOUT2 => cascade2, -- 1-bit output: Cascade 3-state output 41 | SHIFTOUT3 => open, -- 1-bit output: Cascade differential data output 42 | SHIFTOUT4 => open, -- 1-bit output: Cascade differential 3-state output 43 | SHIFTIN1 => '1', -- 1-bit input: Cascade data input 44 | SHIFTIN2 => '1', -- 1-bit input: Cascade 3-state input 45 | SHIFTIN3 => cascade3, -- 1-bit input: Cascade differential data input 46 | SHIFTIN4 => cascade4, -- 1-bit input: Cascade differential 3-state input 47 | TQ => open, -- 1-bit output: 3-state output to pad or IODELAY2 48 | CLK0 => CLK0, -- 1-bit input: I/O clock input 49 | CLK1 => CLK1, -- 1-bit input: Secondary I/O clock input 50 | CLKDIV => CLKDIV, -- 1-bit input: Logic domain clock input 51 | -- D1 - D4: 1-bit (each) input: Parallel data inputs 52 | D1 => ser_data(4), 53 | D2 => '0', 54 | D3 => '0', 55 | D4 => '0', 56 | IOCE => strobe, -- 1-bit input: Data strobe input 57 | OCE => '1', -- 1-bit input: Clock enable input 58 | RST => '0', -- 1-bit input: Asynchrnous reset input 59 | -- T1 - T4: 1-bit (each) input: 3-state control inputs 60 | T1 => '0', 61 | T2 => '0', 62 | T3 => '0', 63 | T4 => '0', 64 | TCE => '1', -- 1-bit input: 3-state clock enable input 65 | TRAIN => '0' -- 1-bit input: Training pattern enable input 66 | ); 67 | 68 | OSERDES2_slave : OSERDES2 69 | generic map ( 70 | BYPASS_GCLK_FF => FALSE, -- Bypass CLKDIV syncronization registers (TRUE/FALSE) 71 | DATA_RATE_OQ => "SDR", -- Output Data Rate ("SDR" or "DDR") 72 | DATA_RATE_OT => "SDR", -- 3-state Data Rate ("SDR" or "DDR") 73 | DATA_WIDTH => 5, -- Parallel data width (2-8) 74 | OUTPUT_MODE => "SINGLE_ENDED", -- "SINGLE_ENDED" or "DIFFERENTIAL" 75 | SERDES_MODE => "SLAVE", -- "NONE", "MASTER" or "SLAVE" 76 | TRAIN_PATTERN => 0 -- Training Pattern (0-15) 77 | ) port map ( 78 | OQ => open, -- 1-bit output: Data output to pad or IODELAY2 79 | SHIFTOUT1 => open, -- 1-bit output: Cascade data output 80 | SHIFTOUT2 => open, -- 1-bit output: Cascade 3-state output 81 | SHIFTOUT3 => cascade3, -- 1-bit output: Cascade differential data output 82 | SHIFTOUT4 => cascade4, -- 1-bit output: Cascade differential 3-state output 83 | SHIFTIN1 => cascade1, -- 1-bit input: Cascade data input 84 | SHIFTIN2 => cascade2, -- 1-bit input: Cascade 3-state input 85 | SHIFTIN3 => '1', -- 1-bit input: Cascade differential data input 86 | SHIFTIN4 => '1', -- 1-bit input: Cascade differential 3-state input 87 | TQ => open, -- 1-bit output: 3-state output to pad or IODELAY2 88 | CLK0 => CLK0, -- 1-bit input: I/O clock input 89 | CLK1 => CLK1, -- 1-bit input: Secondary I/O clock input 90 | CLKDIV => CLKDIV, -- 1-bit input: Logic domain clock input 91 | -- D1 - D4: 1-bit (each) input: Parallel data inputs 92 | D1 => ser_data(0), 93 | D2 => ser_data(1), 94 | D3 => ser_data(2), 95 | D4 => ser_data(3), 96 | IOCE => strobe, -- 1-bit input: Data strobe input 97 | OCE => '1', -- 1-bit input: Clock enable input 98 | RST => '0', -- 1-bit input: Asynchrnous reset input 99 | -- T1 - T4: 1-bit (each) input: 3-state control inputs 100 | T1 => '0', 101 | T2 => '0', 102 | T3 => '0', 103 | T4 => '0', 104 | TCE => '1', -- 1-bit input: 3-state clock enable input 105 | TRAIN => '0' -- 1-bit input: Training pattern enable input 106 | ); 107 | 108 | end Behavioral; 109 | 110 | -------------------------------------------------------------------------------- /FPGA/dvid_out/dvid_out.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- Description: Converts VGA signals into DVID bitstreams. 4 | -- 5 | -- 'blank' must be asserted during the non-display 6 | -- portions of the frame 7 | -- 8 | -- NOTE due to the PLL frequency limits, changes are needed in dvid_out_clocking 9 | -- to select pixel rates between 40 and 100 Mhz pixel clocks, or between 20 and 10 | -- 50 MHz. 11 | -------------------------------------------------------------------------------- 12 | library IEEE; 13 | use IEEE.STD_LOGIC_1164.ALL; 14 | Library UNISIM; 15 | use UNISIM.vcomponents.all; 16 | 17 | entity dvid_out is 18 | Port ( -- Clocking 19 | clk_pixel : IN std_logic; 20 | -- Pixel data 21 | red_p : in STD_LOGIC_VECTOR (7 downto 0); 22 | green_p : in STD_LOGIC_VECTOR (7 downto 0); 23 | blue_p : in STD_LOGIC_VECTOR (7 downto 0); 24 | blank : in STD_LOGIC; 25 | hsync : in STD_LOGIC; 26 | vsync : in STD_LOGIC; 27 | -- TMDS outputs 28 | tmds_out_p : out STD_LOGIC_VECTOR(3 downto 0); 29 | tmds_out_n : out STD_LOGIC_VECTOR(3 downto 0)); 30 | end dvid_out; 31 | 32 | architecture Behavioral of dvid_out is 33 | COMPONENT dvid_out_clocking 34 | PORT( 35 | clk_pixel : IN std_logic; 36 | clk_x1 : OUT std_logic; 37 | clk_x2 : OUT std_logic; 38 | clk_x10 : OUT std_logic; 39 | serdes_strobe : OUT std_logic 40 | ); 41 | END COMPONENT; 42 | 43 | COMPONENT TMDS_encoder 44 | PORT( 45 | clk : IN std_logic; 46 | data : IN std_logic_vector(7 downto 0); 47 | c : IN std_logic_vector(1 downto 0); 48 | blank : IN std_logic; 49 | encoded : OUT std_logic_vector(9 downto 0) 50 | ); 51 | END COMPONENT; 52 | 53 | COMPONENT tmds_out_fifo 54 | PORT ( 55 | wr_clk : IN STD_LOGIC; 56 | rd_clk : IN STD_LOGIC; 57 | din : IN STD_LOGIC_VECTOR(29 DOWNTO 0); 58 | wr_en : IN STD_LOGIC; 59 | rd_en : IN STD_LOGIC; 60 | dout : OUT STD_LOGIC_VECTOR(29 DOWNTO 0); 61 | full : OUT STD_LOGIC; 62 | empty : OUT STD_LOGIC; 63 | prog_empty : OUT STD_LOGIC 64 | ); 65 | END COMPONENT; 66 | 67 | COMPONENT output_serialiser 68 | PORT( 69 | clk_load : IN std_logic; 70 | clk_output : IN std_logic; 71 | strobe : IN std_logic; 72 | ser_data : IN std_logic_vector(4 downto 0); 73 | ser_output : OUT std_logic 74 | ); 75 | END COMPONENT; 76 | 77 | signal clk_x1 : std_logic; 78 | signal clk_x2 : std_logic; 79 | signal clk_x10 : std_logic; 80 | signal serdes_strobe : std_logic; 81 | 82 | signal encoded_red, encoded_green, encoded_blue : std_logic_vector(9 downto 0); 83 | signal ser_in_red, ser_in_green, ser_in_blue, ser_in_clock : std_logic_vector(4 downto 0) := (others => '0'); 84 | 85 | signal rd_enable : std_logic := '0'; 86 | signal toggle : std_logic; 87 | signal toggle_save : std_logic_vector(1 downto 0); 88 | signal red_save, green_save, blue_save : std_logic_vector(9 downto 0) := (others => '0'); 89 | 90 | constant c_red : std_logic_vector(1 downto 0) := (others => '0'); 91 | constant c_green : std_logic_vector(1 downto 0) := (others => '0'); 92 | signal c_blue : std_logic_vector(1 downto 0) := (others => '0'); 93 | 94 | signal red_s : STD_LOGIC; 95 | signal green_s : STD_LOGIC; 96 | signal blue_s : STD_LOGIC; 97 | signal clock_s : STD_LOGIC; 98 | 99 | begin 100 | -- Send the pixels to the encoder 101 | c_blue <= vsync & hsync; 102 | TMDS_encoder_red: TMDS_encoder PORT MAP(clk => clk_pixel, data => red_p, c => c_red, blank => blank, encoded => encoded_red); 103 | TMDS_encoder_blue: TMDS_encoder PORT MAP(clk => clk_pixel, data => blue_p, c => c_blue, blank => blank, encoded => encoded_blue); 104 | TMDS_encoder_green: TMDS_encoder PORT MAP(clk => clk_pixel, data => green_p, c => c_green, blank => blank, encoded => encoded_green); 105 | 106 | -- Then to a small FIFO 107 | -- fifo_in <= encoded_red & encoded_green & encoded_blue; 108 | 109 | Inst_dvid_out_clocking: dvid_out_clocking PORT MAP( 110 | clk_pixel => clk_pixel, 111 | clk_x1 => clk_x1, 112 | clk_x2 => clk_x2, 113 | clk_x10 => clk_x10, 114 | serdes_strobe => serdes_strobe 115 | ); 116 | 117 | process(clk_pixel) 118 | begin 119 | if rising_edge(clk_pixel) then 120 | toggle <= not toggle; 121 | end if; 122 | end process; 123 | -- Now at a x2 clock, send the data from the fifo to the serialisers 124 | process(clk_x2) 125 | begin 126 | if rising_edge(clk_x2) then 127 | if toggle_save(1) = toggle_save(0) then 128 | ser_in_red <= red_save(9 downto 5); 129 | ser_in_green <= green_save(9 downto 5); 130 | ser_in_blue <= blue_save(9 downto 5); 131 | ser_in_clock <= "11111"; 132 | else 133 | ser_in_red <= red_save(4 downto 0); 134 | ser_in_green <= green_save(4 downto 0); 135 | ser_in_blue <= blue_save(4 downto 0); 136 | ser_in_clock <= "00000"; 137 | end if; 138 | toggle_save <= toggle_save(0) & toggle; 139 | red_save <= encoded_red; 140 | green_save <= encoded_green; 141 | blue_save <= encoded_blue; 142 | end if; 143 | end process; 144 | 145 | -- The Seraialisers 146 | output_serialiser_r: output_serialiser PORT MAP(clk_load => clk_x2, clk_output => clk_x10, strobe => serdes_strobe, ser_data => ser_in_red, ser_output => red_s); 147 | output_serialiser_b: output_serialiser PORT MAP(clk_load => clk_x2, clk_output => clk_x10, strobe => serdes_strobe, ser_data => ser_in_blue, ser_output => blue_s); 148 | output_serialiser_g: output_serialiser PORT MAP(clk_load => clk_x2, clk_output => clk_x10, strobe => serdes_strobe, ser_data => ser_in_green, ser_output => green_s); 149 | output_serialiser_c: output_serialiser PORT MAP(clk_load => clk_x2, clk_output => clk_x10, strobe => serdes_strobe, ser_data => ser_in_clock, ser_output => clock_s); 150 | 151 | -- The output buffers/drivers 152 | OBUFDS_blue : OBUFDS port map ( O => tmds_out_p(0), OB => tmds_out_n(0), I => blue_s); 153 | OBUFDS_green : OBUFDS port map ( O => tmds_out_p(1), OB => tmds_out_n(1), I => green_s); 154 | OBUFDS_red : OBUFDS port map ( O => tmds_out_p(2), OB => tmds_out_n(2), I => red_s); 155 | OBUFDS_clock : OBUFDS port map ( O => tmds_out_p(3), OB => tmds_out_n(3), I => clock_s); 156 | 157 | end Behavioral; -------------------------------------------------------------------------------- /FPGA/fpga_matrix.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Company: 3 | -- Engineer: 4 | -- 5 | -- Create Date: 15:13:30 01/03/2015 6 | -- Design Name: 7 | -- Module Name: dvid_thru - Behavioral 8 | -- Project Name: 9 | -- Target Devices: 10 | -- Tool versions: 11 | -- Description: 12 | -- 13 | -- Dependencies: 14 | -- 15 | -- Revision: 16 | -- Revision 0.01 - File Created 17 | -- Additional Comments: 18 | -- 19 | ---------------------------------------------------------------------------------- 20 | library IEEE; 21 | use IEEE.STD_LOGIC_1164.ALL; 22 | use IEEE.NUMERIC_STD.ALL; 23 | use IEEE.STD_LOGIC_MISC.ALL; 24 | 25 | use work.rgbmatrix.all; -- Constants & Configuration 26 | 27 | entity fpga_matrix is 28 | Port ( 29 | --clk50 : in std_logic; 30 | hdmi_in_p : in std_logic_vector(3 downto 0); 31 | hdmi_in_n : in std_logic_vector(3 downto 0); 32 | hdmi_in_sclk : inout std_logic; 33 | hdmi_in_sdat : inout std_logic; 34 | 35 | hdmi_out_p : out std_logic_vector(3 downto 0); 36 | hdmi_out_n : out std_logic_vector(3 downto 0); 37 | 38 | port_a : out std_logic_vector(11 downto 0); 39 | port_b : out std_logic_vector(5 downto 0); 40 | 41 | leds : out std_logic_vector(7 downto 0); 42 | switch : in std_logic_vector(0 downto 0) 43 | ); 44 | end fpga_matrix; 45 | 46 | architecture Behavioral of fpga_matrix is 47 | 48 | signal rst : std_logic; 49 | 50 | -- Video clocks 51 | signal clk_x1 : std_logic; 52 | signal clk_x2 : std_logic; 53 | signal clk_x10 : std_logic; 54 | signal strobe : std_logic; 55 | 56 | -- Video signals 57 | signal i_red : std_logic_vector(7 downto 0); 58 | signal i_green : std_logic_vector(7 downto 0); 59 | signal i_blue : std_logic_vector(7 downto 0); 60 | signal i_blank : std_logic; 61 | signal i_hsync : std_logic; 62 | signal i_vsync : std_logic; 63 | 64 | signal o_red : std_logic_vector(7 downto 0); 65 | signal o_green : std_logic_vector(7 downto 0); 66 | signal o_blue : std_logic_vector(7 downto 0); 67 | signal o_blank : std_logic; 68 | signal o_hsync : std_logic; 69 | signal o_vsync : std_logic; 70 | 71 | -- Memory signals 72 | signal wr_enable : std_logic; 73 | signal wr_addr : std_logic_vector(ADDR_WIDTH - 1 downto 0); 74 | signal wr_data : std_logic_vector(DATA_WIDTH - 1 downto 0); 75 | 76 | signal rd_addr : std_logic_vector(ADDR_WIDTH - 2 downto 0); 77 | signal rd_data : std_logic_vector(DATA_WIDTH * 2 - 1 downto 0); 78 | 79 | -- Debug signals 80 | signal channel_a : std_logic; 81 | signal channel_b : std_logic; 82 | signal clk_count : unsigned(2 downto 0) := (others => '0'); 83 | signal clk_out : std_logic; 84 | 85 | begin 86 | 87 | rst <= switch(0); 88 | port_a(10) <= '0'; 89 | port_a(11) <= '0'; 90 | 91 | ---------------- 92 | -- Debug outputs 93 | ---------------- 94 | port_b(3) <= channel_a; 95 | port_b(4) <= channel_b; 96 | port_b(5) <= clk_out; 97 | 98 | channel_a <= i_hsync; 99 | channel_b <= i_vsync; 100 | 101 | ------------------------------------- 102 | -- EDID I2C signals (not implemented) 103 | ------------------------------------- 104 | hdmi_in_sclk <= 'Z'; 105 | hdmi_in_sdat <= 'Z'; 106 | 107 | ------------------------------------------------- 108 | -- Read the VGA signals from the DVI-D/TMDS input 109 | ------------------------------------------------- 110 | Inst_dvid_in: entity work.dvid_in port map ( 111 | tmds_in_p => hdmi_in_p, 112 | tmds_in_n => hdmi_in_n, 113 | 114 | leds => leds, 115 | 116 | clk_x1 => clk_x1, 117 | clk_x2 => clk_x2, 118 | clk_x10 => clk_x10, 119 | strobe => strobe, 120 | 121 | red_p => i_red, 122 | green_p => i_green, 123 | blue_p => i_blue, 124 | blank => i_blank, 125 | hsync => i_hsync, 126 | vsync => i_vsync 127 | ); 128 | 129 | -------------------------------------------- 130 | -- Fill the framebuffer from the HDMI signal 131 | -------------------------------------------- 132 | Inst_display: entity work.display port map ( 133 | clk_pixel => clk_x1, 134 | i_red => i_red, 135 | i_green => i_green, 136 | i_blue => i_blue, 137 | i_blank => i_blank, 138 | i_hsync => i_hsync, 139 | i_vsync => i_vsync, 140 | 141 | o_red => o_red, 142 | o_green => o_green, 143 | o_blue => o_blue, 144 | o_blank => o_blank, 145 | o_hsync => o_hsync, 146 | o_vsync => o_vsync, 147 | 148 | wr_enable => wr_enable, 149 | wr_addr => wr_addr, 150 | wr_data => wr_data 151 | ); 152 | 153 | --------------------------------------------------- 154 | -- Convert the VGA signals to the DVI-D/TMDS output 155 | --------------------------------------------------- 156 | Inst_dvid_out: entity work.dvid_out port map ( 157 | clk_pixel => clk_x1, 158 | 159 | red_p => o_red, 160 | green_p => o_green, 161 | blue_p => o_blue, 162 | blank => o_blank, 163 | hsync => o_hsync, 164 | vsync => o_vsync, 165 | 166 | tmds_out_p => hdmi_out_p, 167 | tmds_out_n => hdmi_out_n 168 | ); 169 | 170 | ------------------------------------- 171 | -- Special memory for the framebuffer 172 | ------------------------------------- 173 | Inst_memory: entity work.memory port map ( 174 | -- Writing side 175 | wr_clk => clk_x1, 176 | wr_enable => wr_enable, 177 | wr_addr => wr_addr, 178 | wr_data => wr_data, 179 | 180 | -- Reading side 181 | rd_clk => clk_x2, 182 | rd_addr => rd_addr, 183 | rd_data => rd_data 184 | ); 185 | 186 | ----------------------- 187 | -- LED panel controller 188 | ----------------------- 189 | Inst_ledctrl: entity work.ledctrl port map ( 190 | rst => rst, 191 | clk_in => clk_x1, 192 | 193 | -- Connection to LED panel 194 | rgb1(2) => port_a(0), 195 | rgb1(1) => port_a(2), 196 | rgb1(0) => port_a(4), 197 | rgb2(2) => port_a(1), 198 | rgb2(1) => port_a(3), 199 | rgb2(0) => port_a(5), 200 | led_addr(3 downto 0) => port_a(9 downto 6), 201 | clk_out => port_b(0), 202 | lat => port_b(1), 203 | oe => port_b(2), 204 | 205 | -- Connection with framebuffer 206 | rd_addr => rd_addr, 207 | rd_data => rd_data 208 | ); 209 | 210 | ------------------------ 211 | -- Output clk_pixel / 16 212 | ------------------------ 213 | process(clk_x1) 214 | begin 215 | if rising_edge(clk_x1) then 216 | clk_count <= clk_count + 1; 217 | if clk_count = "000" then 218 | clk_out <= not clk_out; 219 | end if; 220 | end if; 221 | end process; 222 | 223 | end Behavioral; 224 | 225 | -------------------------------------------------------------------------------- /FPGA/ledctrl.vhd: -------------------------------------------------------------------------------- 1 | -- Adafruit RGB LED Matrix Display Driver 2 | -- Finite state machine to control the LED matrix hardware 3 | -- 4 | -- Copyright (c) 2012 Brian Nezvadovitz 5 | -- This software is distributed under the terms of the MIT License shown below. 6 | -- 7 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 8 | -- of this software and associated documentation files (the "Software"), to 9 | -- deal in the Software without restriction, including without limitation the 10 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | -- sell copies of the Software, and to permit persons to whom the Software is 12 | -- furnished to do so, subject to the following conditions: 13 | -- 14 | -- The above copyright notice and this permission notice shall be included in 15 | -- all copies or substantial portions of the Software. 16 | -- 17 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | -- IN THE SOFTWARE. 24 | 25 | -- For some great documentation on how the RGB LED panel works, see this page: 26 | -- http://www.rayslogic.com/propeller/Programming/AdafruitRGB/AdafruitRGB.htm 27 | -- or this page 28 | -- http://www.ladyada.net/wiki/tutorials/products/rgbledmatrix/index.html#how_the_matrix_works 29 | 30 | library ieee; 31 | use ieee.std_logic_1164.all; 32 | use ieee.numeric_std.all; 33 | 34 | use work.rgbmatrix.all; 35 | 36 | entity ledctrl is 37 | port ( 38 | clk_in : in std_logic; 39 | rst : in std_logic; 40 | 41 | -- LED Panel IO 42 | rgb1 : out std_logic_vector(2 downto 0); 43 | rgb2 : out std_logic_vector(2 downto 0); 44 | led_addr : out std_logic_vector(3 downto 0); 45 | clk_out : out std_logic; 46 | lat : out std_logic; 47 | oe : out std_logic; 48 | 49 | -- Memory IO 50 | rd_addr : out std_logic_vector(ADDR_WIDTH - 2 downto 0); 51 | rd_data : in std_logic_vector(DATA_WIDTH * 2 - 1 downto 0) 52 | ); 53 | end ledctrl; 54 | 55 | architecture bhv of ledctrl is 56 | -- Internal signals 57 | signal clk : std_logic; 58 | 59 | -- Essential state machine signals 60 | type STATE_TYPE is (INIT, READ_PIXEL_DATA, INCR_RAM_ADDR, LATCH, INCR_LED_ADDR); 61 | signal state, next_state : STATE_TYPE; 62 | 63 | -- State machine signals 64 | signal col_count, next_col_count : unsigned(IMG_WIDTH_LOG2 downto 0); 65 | signal bpp_count, next_bpp_count : unsigned(PIXEL_DEPTH - 1 downto 0); 66 | signal s_led_addr, next_led_addr : std_logic_vector(3 downto 0); 67 | signal s_ram_addr, next_ram_addr : std_logic_vector(ADDR_WIDTH - 2 downto 0); 68 | signal s_rgb1, next_rgb1, s_rgb2, next_rgb2 : std_logic_vector(2 downto 0); 69 | signal s_oe, s_lat, s_clk_out : std_logic; 70 | begin 71 | 72 | clk <= clk_in; 73 | 74 | -- Breakout internal signals to the output port 75 | led_addr <= s_led_addr; 76 | -- Fix address computation 77 | rd_addr <= std_logic_vector(unsigned(s_ram_addr) + 1); 78 | rgb1 <= s_rgb1; 79 | rgb2 <= s_rgb2; 80 | oe <= s_oe; 81 | lat <= s_lat; 82 | clk_out <= s_clk_out; 83 | 84 | -- State register 85 | process(rst, clk) 86 | begin 87 | if (rst = '1') then 88 | state <= INIT; 89 | col_count <= (others => '0'); 90 | bpp_count <= (others => '0'); 91 | 92 | -- this inits to 111 because the led_addr is actually used *after* 93 | -- the incoming data is latched by the panel (not while being 94 | -- shifted in), so by then it has been "incremented" to 000 95 | s_led_addr <= (others => '1'); 96 | s_ram_addr <= (others => '1'); 97 | 98 | s_rgb1 <= (others => '0'); 99 | s_rgb2 <= (others => '0'); 100 | elsif (rising_edge(clk)) then 101 | state <= next_state; 102 | col_count <= next_col_count; 103 | bpp_count <= next_bpp_count; 104 | s_led_addr <= next_led_addr; 105 | s_ram_addr <= next_ram_addr; 106 | s_rgb1 <= next_rgb1; 107 | s_rgb2 <= next_rgb2; 108 | end if; 109 | end process; 110 | 111 | -- Next-state logic 112 | process(state, col_count, bpp_count, s_led_addr, s_ram_addr, s_rgb1, s_rgb2, rd_data) is 113 | -- Internal breakouts 114 | variable upper, lower : unsigned(DATA_WIDTH - 1 downto 0); 115 | variable upper_r, upper_g, upper_b : unsigned(PIXEL_DEPTH - 1 downto 0); 116 | variable lower_r, lower_g, lower_b : unsigned(PIXEL_DEPTH - 1 downto 0); 117 | variable r1, g1, b1, r2, g2, b2 : std_logic; 118 | begin 119 | 120 | r1 := '0'; g1 := '0'; b1 := '0'; -- Defaults 121 | r2 := '0'; g2 := '0'; b2 := '0'; -- Defaults 122 | 123 | -- Default register next-state assignments 124 | next_col_count <= col_count; 125 | next_bpp_count <= bpp_count; 126 | next_led_addr <= s_led_addr; 127 | next_ram_addr <= s_ram_addr; 128 | next_rgb1 <= s_rgb1; 129 | next_rgb2 <= s_rgb2; 130 | 131 | -- Default signal assignments 132 | s_clk_out <= '0'; 133 | s_lat <= '0'; 134 | s_oe <= '1'; -- this signal is "active low" 135 | 136 | -- States 137 | case state is 138 | when INIT => 139 | if(s_led_addr = "1111") then 140 | if (bpp_count = unsigned(to_signed(-2, PIXEL_DEPTH))) then 141 | next_bpp_count <= (others => '0'); 142 | else 143 | next_bpp_count <= bpp_count + 1; 144 | end if; 145 | end if; 146 | next_state <= READ_PIXEL_DATA; 147 | when READ_PIXEL_DATA => 148 | s_oe <= '0'; -- enable display 149 | -- Do parallel comparisons against BPP counter to gain multibit color 150 | if(upper_r > bpp_count) then 151 | r1 := '1'; 152 | end if; 153 | if(upper_g > bpp_count) then 154 | g1 := '1'; 155 | end if; 156 | if(upper_b > bpp_count) then 157 | b1 := '1'; 158 | end if; 159 | if(lower_r > bpp_count) then 160 | r2 := '1'; 161 | end if; 162 | if(lower_g > bpp_count) then 163 | g2 := '1'; 164 | end if; 165 | if(lower_b > bpp_count) then 166 | b2 := '1'; 167 | end if; 168 | next_col_count <= col_count + 1; -- update/increment column counter 169 | if(col_count < IMG_WIDTH) then -- check if at the rightmost side of the image 170 | next_state <= INCR_RAM_ADDR; 171 | else 172 | next_state <= INCR_LED_ADDR; 173 | end if; 174 | when INCR_RAM_ADDR => 175 | s_clk_out <= '1'; -- pulse the output clock 176 | s_oe <= '0'; -- enable display 177 | next_ram_addr <= std_logic_vector(unsigned(s_ram_addr) + 1); 178 | next_state <= READ_PIXEL_DATA; 179 | when INCR_LED_ADDR => 180 | -- display is disabled during led_addr (select lines) update 181 | next_led_addr <= std_logic_vector(unsigned(s_led_addr) + 1); 182 | next_col_count <= (others => '0'); -- reset the column counter 183 | next_state <= LATCH; 184 | when LATCH => 185 | -- display is disabled during latching 186 | s_lat <= '1'; -- latch the data 187 | next_state <= INIT; -- restart state machine 188 | end case; 189 | 190 | -- Pixel data is given as 2 combined words, with the upper half containing 191 | -- the upper pixel and the lower half containing the lower pixel. Inside 192 | -- each half the pixel data is encoded in RGB order with multiple repeated 193 | -- bits for each subpixel depending on the chosen color depth. For example, 194 | -- a PIXEL_DEPTH of 3 results in a 18-bit word arranged RRRGGGBBBrrrgggbbb. 195 | -- The following assignments break up this encoding into the human-readable 196 | -- signals used above, or reconstruct it into LED data signals. 197 | upper := unsigned(rd_data(DATA_WIDTH * 2 - 1 downto DATA_WIDTH)); 198 | lower := unsigned(rd_data(DATA_WIDTH - 1 downto 0)); 199 | upper_r := upper(3 * PIXEL_DEPTH - 1 downto 2 * PIXEL_DEPTH); 200 | upper_g := upper(2 * PIXEL_DEPTH - 1 downto PIXEL_DEPTH); 201 | upper_b := upper( PIXEL_DEPTH - 1 downto 0); 202 | lower_r := lower(3 * PIXEL_DEPTH - 1 downto 2 * PIXEL_DEPTH); 203 | lower_g := lower(2 * PIXEL_DEPTH - 1 downto PIXEL_DEPTH); 204 | lower_b := lower( PIXEL_DEPTH - 1 downto 0); 205 | next_rgb1 <= r1 & g1 & b1; 206 | next_rgb2 <= r2 & g2 & b2; 207 | 208 | end process; 209 | 210 | end bhv; -------------------------------------------------------------------------------- /FPGA/dvid_in/dvid_in.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Engineer: Mike Field 3 | -- 4 | -- Module Name: dvi_in.vhd - Behavioral 5 | -- 6 | -- Description: Design to capture raw DVI-D input 7 | -- 8 | -- I've also got do do some work to automatically adjust the phase of the 9 | -- bit clocks, at the moment it needs to be manually tuned to match your source 10 | ---------------------------------------------------------------------------------- 11 | library IEEE; 12 | use IEEE.STD_LOGIC_1164.ALL; 13 | use IEEE.NUMERIC_STD.ALL; 14 | 15 | library UNISIM; 16 | use UNISIM.VComponents.all; 17 | 18 | entity dvid_in is 19 | Port ( 20 | -- DVI-D/HDMI signals 21 | tmds_in_p : in STD_LOGIC_VECTOR(3 downto 0); 22 | tmds_in_n : in STD_LOGIC_VECTOR(3 downto 0); 23 | -- debug 24 | leds : out std_logic_vector(7 downto 0) := (others => '0'); 25 | -- Clocking 26 | clk_x1 : out std_logic; 27 | clk_x2 : out std_logic; 28 | clk_x10 : out std_logic; 29 | strobe : out std_logic; 30 | -- VGA signals 31 | red_p : out std_logic_vector(7 downto 0) := (others => '0'); 32 | green_p : out std_logic_vector(7 downto 0) := (others => '0'); 33 | blue_p : out std_logic_vector(7 downto 0) := (others => '0'); 34 | hsync : out std_logic := '0'; 35 | vsync : out std_logic := '0'; 36 | blank : out std_logic := '0' 37 | ); 38 | end dvid_in; 39 | 40 | architecture Behavioral of dvid_in is 41 | signal dvid_clk : std_logic; 42 | signal dvid_clk_buffered : std_logic; 43 | signal ioclock : std_logic; 44 | signal serdes_strobe : std_logic; 45 | 46 | signal clock_x1 : std_logic; 47 | signal clock_x2 : std_logic; 48 | signal clock_x10 : std_logic; 49 | signal clock_x10_unbuffered : std_logic; 50 | signal clock_x2_unbuffered : std_logic; 51 | signal clock_x1_unbuffered : std_logic; 52 | 53 | signal clk_feedback : std_logic; 54 | signal pll_locked : std_logic; 55 | signal sync_seen : std_logic; 56 | 57 | signal c0_d : std_logic_vector(7 downto 0); 58 | signal c0_c : std_logic_vector(1 downto 0); 59 | signal c0_active : std_logic; 60 | 61 | signal c1_d : std_logic_vector(7 downto 0); 62 | signal c1_c : std_logic_vector(1 downto 0); 63 | signal c1_active : std_logic; 64 | 65 | signal c2_d : std_logic_vector(7 downto 0); 66 | signal c2_c : std_logic_vector(1 downto 0); 67 | signal c2_active : std_logic; 68 | 69 | 70 | signal led_count : unsigned( 2 downto 0) := (others => '0'); 71 | signal framing : std_logic_vector(3 downto 0) := (others => '0'); 72 | signal since_sync : unsigned(14 downto 0) := (others => '0'); 73 | 74 | signal start_calibrate : std_logic; 75 | signal reset_delay : std_logic; 76 | signal cal_start_count : unsigned(7 downto 0) := (others => '0'); 77 | 78 | COMPONENT input_channel 79 | GENERIC( 80 | fixed_delay : in natural 81 | ); 82 | PORT( 83 | clk_fabric : IN std_logic; 84 | clk_fabric_x2 : IN std_logic; 85 | clk_input : IN std_logic; 86 | strobe : IN std_logic; 87 | tmds_p : in STD_LOGIC; 88 | tmds_n : in STD_LOGIC; 89 | invert : IN std_logic; 90 | framing : IN std_logic_vector(3 downto 0); 91 | data_out : OUT std_logic_vector(7 downto 0); 92 | control : OUT std_logic_vector(1 downto 0); 93 | active_data : OUT std_logic; 94 | sync_seen : OUT std_logic; 95 | 96 | adjust_delay : IN std_logic; 97 | increase_delay : IN std_logic; 98 | reset_delay : IN std_logic; 99 | start_calibrate : IN std_logic; 100 | calibrate_busy : OUT std_logic 101 | ); 102 | END COMPONENT; 103 | 104 | signal x : unsigned(12 downto 0) := (others => '0'); 105 | signal y : unsigned(12 downto 0) := (others => '0'); 106 | begin 107 | ---------------------------------- 108 | -- Output the decoded VGA signals 109 | ---------------------------------- 110 | clk_x1 <= clock_x1; 111 | clk_x2 <= clock_x2; 112 | clk_x10 <= clock_x10; 113 | strobe <= serdes_strobe; 114 | 115 | blue_p <= c0_d; 116 | green_p <= c1_d; 117 | red_p <= c2_d; 118 | hsync <= c0_c(0); --c2 119 | vsync <= c0_c(1); --c2 120 | blank <= not c2_active; 121 | 122 | ---------------------------------- 123 | -- Debug 124 | ---------------------------------- 125 | leds <= c2_c & (not c2_c) & framing; 126 | 127 | 128 | ------------------------------------------ 129 | -- Receive the differential clock 130 | ------------------------------------------ 131 | clk_diff_input : IBUFDS 132 | generic map ( 133 | DIFF_TERM => FALSE, 134 | IBUF_LOW_PWR => TRUE, 135 | IOSTANDARD => "TMDS_33") 136 | port map ( 137 | O => dvid_clk, 138 | I => tmds_in_p(3), 139 | IB => tmds_in_n(3) 140 | ); 141 | 142 | ------------------------------------------ 143 | -- Buffer it before the PLL 144 | ------------------------------------------ 145 | BUFG_clk : BUFG port map ( I => dvid_clk, O => dvid_clk_buffered); 146 | 147 | ------------------------------------------ 148 | -- Generate the bit clocks for the serdes 149 | -- 150 | -- Adjust the phase in a 10:2:1 ratio (e.g. 50:10:5) 151 | ------------------------------------------ 152 | PLL_BASE_inst : PLL_BASE 153 | generic map ( 154 | CLKFBOUT_MULT => 10, 155 | -- Almost works with Western Digital Live @ 720p/60 -Noise on blue channel. 156 | --CLKOUT0_DIVIDE => 1, CLKOUT0_PHASE => 200.0, -- Output 10x original frequency 157 | --CLKOUT1_DIVIDE => 5, CLKOUT1_PHASE => 40.0, -- Output 2x original frequency 158 | --CLKOUT2_DIVIDE => 10, CLKOUT2_PHASE => 20.0, -- Output 1x original frequency 159 | -- Works with Western Digital Live @ 640x480/60Hz 160 | CLKOUT0_DIVIDE => 1, CLKOUT0_PHASE => 0.0, -- Output 10x original frequency 161 | CLKOUT1_DIVIDE => 5, CLKOUT1_PHASE => 0.0, -- Output 2x original frequency 162 | CLKOUT2_DIVIDE => 10, CLKOUT2_PHASE => 0.0, -- Output 1x original frequency 163 | CLK_FEEDBACK => "CLKFBOUT", -- Clock source to drive CLKFBIN ("CLKFBOUT" or "CLKOUT0") 164 | CLKIN_PERIOD => 10.0, -- IMPORTANT! Approx 77 MHz 165 | DIVCLK_DIVIDE => 1 -- Division value for all output clocks (1-52) 166 | ) 167 | port map ( 168 | CLKFBOUT => clk_feedback, 169 | CLKOUT0 => clock_x10_unbuffered, 170 | CLKOUT1 => clock_x2_unbuffered, 171 | CLKOUT2 => clock_x1_unbuffered, 172 | CLKOUT3 => open, 173 | CLKOUT4 => open, 174 | CLKOUT5 => open, 175 | LOCKED => pll_locked, 176 | CLKFBIN => clk_feedback, 177 | CLKIN => dvid_clk_buffered, 178 | RST => '0' -- 1-bit input: Reset input 179 | ); 180 | 181 | BUFG_pclockx2 : BUFG port map ( I => clock_x2_unbuffered, O => clock_x2); 182 | BUFG_pclock : BUFG port map ( I => clock_x1_unbuffered, O => clock_x1); 183 | BUFG_pclockx10 : BUFG port map ( I => clock_x10_unbuffered, O => clock_x10 ); 184 | 185 | 186 | ------------------------------------------------ 187 | -- Buffer the clocks ready to go the serialisers 188 | ------------------------------------------------ 189 | BUFPLL_inst : BUFPLL 190 | generic map ( 191 | DIVIDE => 5, -- DIVCLK divider (1-8) !!!! IMPORTANT TO CHANGE THIS AS NEEDED !!!! 192 | ENABLE_SYNC => TRUE -- Enable synchrnonization between PLL and GCLK (TRUE/FALSE) -- should be true 193 | ) 194 | port map ( 195 | IOCLK => ioclock, -- Clock used to receive bits 196 | LOCK => open, 197 | SERDESSTROBE => serdes_strobe, -- Clock use to load data into SERDES 198 | GCLK => clock_x2, -- Global clock use as a reference for serdes_strobe 199 | LOCKED => pll_locked, -- When the upstream PLL is locked 200 | PLLIN => clock_x10_unbuffered -- Clock to use for bit capture - this must be unbuffered 201 | ); 202 | 203 | ---------------------------------------- 204 | -- c0 channel input - Carries the RED channel 205 | ---------------------------------------- 206 | input_channel_c0: input_channel GENERIC MAP( 207 | fixed_delay => 30 208 | ) PORT MAP( 209 | clk_fabric => clock_x1, 210 | clk_fabric_x2 => clock_x2, 211 | clk_input => ioclock, 212 | strobe => serdes_strobe, 213 | tmds_p => tmds_in_p(0), 214 | tmds_n => tmds_in_n(0), 215 | invert => '0', 216 | framing => framing, 217 | data_out => c0_d, 218 | control => c0_c, 219 | active_data => c0_active, 220 | sync_seen => open, 221 | adjust_delay => '0', 222 | increase_delay => '0', 223 | reset_delay => reset_delay, 224 | start_calibrate => start_calibrate, 225 | calibrate_busy => open 226 | ); 227 | 228 | ---------------------------------------- 229 | -- c1 channel input - Carries the BLUE channel 230 | ---------------------------------------- 231 | 232 | input_channel_c1: input_channel GENERIC MAP( 233 | fixed_delay => 40 234 | ) PORT MAP( 235 | clk_fabric => clock_x1, 236 | clk_fabric_x2 => clock_x2, 237 | clk_input => ioclock, 238 | strobe => serdes_strobe, 239 | tmds_p => tmds_in_p(1), 240 | tmds_n => tmds_in_n(1), 241 | invert => '0', 242 | framing => framing, 243 | data_out => c1_d, 244 | control => c1_c, 245 | active_data => c1_active, 246 | sync_seen => open, 247 | adjust_delay => '0', 248 | increase_delay => '0', 249 | reset_delay => reset_delay, 250 | start_calibrate => start_calibrate, 251 | calibrate_busy => open 252 | ); 253 | 254 | ---------------------------------------- 255 | -- c2 channel input - Carries the GREEN channel and syncs 256 | ---------------------------------------- 257 | input_channel_c2: input_channel GENERIC MAP( 258 | fixed_delay => 30 259 | ) PORT MAP( 260 | clk_fabric => clock_x1, 261 | clk_fabric_x2 => clock_x2, 262 | clk_input => ioclock, 263 | strobe => serdes_strobe, 264 | tmds_p => tmds_in_p(2), 265 | tmds_n => tmds_in_n(2), 266 | invert => '0', 267 | framing => framing, 268 | data_out => c2_d, 269 | control => c2_c, 270 | active_data => c2_active, 271 | sync_seen => sync_seen, 272 | adjust_delay => '0', 273 | increase_delay => '0', 274 | reset_delay => reset_delay, 275 | start_calibrate => start_calibrate, 276 | calibrate_busy => open 277 | ); 278 | 279 | calibrate_process: process (clock_x2) 280 | begin 281 | if rising_edge(clock_x2) then 282 | if cal_start_count = "10000000" then 283 | start_calibrate <= '0'; 284 | else 285 | start_calibrate <= '0'; 286 | end if; 287 | if cal_start_count = "11111100" then 288 | reset_delay <= '0'; 289 | else 290 | reset_delay <= '0'; 291 | end if; 292 | 293 | if cal_start_count /= "11111111" then 294 | cal_start_count <= cal_start_count + 1; 295 | end if; 296 | end if; 297 | end process; 298 | 299 | process(clock_x1) 300 | begin 301 | if rising_edge(clock_x1) then 302 | -- Work out what we need to do to frame the TMDS data correctly 303 | if sync_seen = '1' then 304 | ------------------------------------------------------------ 305 | -- We've just seen a sync codeword, so restart the counter 306 | -- This means that we are in sync 307 | ------------------------------------------------------------ 308 | since_sync <= (others => '0'); 309 | elsif since_sync = "111111111111111" then 310 | ------------------------------------------------------------ 311 | -- We haven't seen a sync in 16383 pixel cycles, so it can't 312 | -- be in sync. By incrementing 'framing' we bitslip one bit. 313 | -- 314 | -- The 16k number is special, as they two sync codewords 315 | -- being looked for will not be seen during the VSYNC period 316 | -- (assuming that you are looking in the channel that 317 | -- includes the encoded HSYNC/VSYNC signals 318 | ------------------------------------------------------------ 319 | if framing = "1001" then 320 | framing <= (others =>'0'); 321 | else 322 | framing <= std_logic_vector(unsigned(framing) + 1); 323 | end if; 324 | since_sync <= since_sync + 1; 325 | else 326 | ------------------------------------------------------------ 327 | -- Keep counting and hoping for a sync codeword 328 | ------------------------------------------------------------ 329 | since_sync <= since_sync + 1; 330 | end if; 331 | 332 | end if; 333 | end process; 334 | end Behavioral; -------------------------------------------------------------------------------- /FPGA/fpga_matrix.xise: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 |
419 | --------------------------------------------------------------------------------