DVI support -- initial demo works
authormegacz <adam@megacz.com>
Sun, 8 Mar 2009 18:56:49 +0000 (11:56 -0700)
committermegacz <adam@megacz.com>
Sun, 8 Mar 2009 18:56:49 +0000 (11:56 -0700)
Makefile
ships/Dvi.ship
src/edu/berkeley/fleet/fpga/dvi/dvi_video_test.vhd [new file with mode: 0644]
src/edu/berkeley/fleet/fpga/dvi/i2c_core.vhd [new file with mode: 0644]
src/edu/berkeley/fleet/fpga/dvi/i2c_video_programmer.vhd [new file with mode: 0644]
src/edu/berkeley/fleet/fpga/dvi/vga_timing_decode.vhd [new file with mode: 0644]
src/edu/berkeley/fleet/fpga/dvi/vga_timing_generator.vhd [new file with mode: 0644]

index b12d896..6d99fce 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -112,11 +112,13 @@ synth:
        cd build/fpga; ln -sf ../../src/edu/berkeley/fleet/fpga/* .
        cd build/fpga; ln -sf ../../src/edu/berkeley/fleet/fpga/mem/* .
        cd build/fpga; ln -sf ../../src/edu/berkeley/fleet/fpga/ddr2/* .
+       cd build/fpga; ln -sf ../../src/edu/berkeley/fleet/fpga/dvi/* .
        #cd build/fpga; ln -sf ../../src/edu/berkeley/fleet/fpga/greg/* .
        rm -f build/fpga/main.lso
        echo work                        >> build/fpga/main.lso
        rm -f build/fpga/main.prj
        cd build/fpga; for A in *.v;   do echo verilog work \""$$A"\"; done >> main.prj
+       cd build/fpga; for A in *.vhd; do echo vhdl    work \""$$A"\"; done >> main.prj
        cd build/fpga; touch main.ini
        cd build/fpga; mkdir -p tmp
        cd build/fpga; mkdir -p xst
index 4541769..3d88be3 100644 (file)
@@ -25,30 +25,86 @@ percolate up:    dvi_xclk_p  1
 percolate up:    dvi_de      1
 percolate up:    dvi_reset_b 1
 
+percolate down:  gpio_sw_c    1
+
 percolate up:    gpio_led_c   1
 percolate up:    gpio_led_e   1
 percolate up:    gpio_led_n   1
 percolate up:    gpio_led_s   1
 percolate up:    gpio_led_w   1
 
+percolate up:    gpio_led_0   1
+percolate up:    gpio_led_1   1
+percolate up:    gpio_led_2   1
+percolate up:    gpio_led_3   1
 percolate up:    gpio_led_4   1
 percolate up:    gpio_led_5   1
 percolate up:    gpio_led_6   1
 percolate up:    gpio_led_7   1
 
-== TeX ==============================================================
+percolate down:  dvi_gpio1   1
+percolate up:    dvi_iic_scl 1
+percolate inout: dvi_iic_sda 1
 
-== Fleeterpreter ====================================================
-//percolate down:  dvi_gpio1   1
-//percolate up:    dvi_iic_scl 1
-//percolate inout: dvi_iic_sda 1
+== FPGA ==============================================================
 
-  public void service() { }
+wire [11:0] dvi_d;
+assign dvi_d0  = dvi_d[0];
+assign dvi_d1  = dvi_d[1];
+assign dvi_d2  = dvi_d[2];
+assign dvi_d3  = dvi_d[3];
+assign dvi_d4  = dvi_d[4];
+assign dvi_d5  = dvi_d[5];
+assign dvi_d6  = dvi_d[6];
+assign dvi_d7  = dvi_d[7];
+assign dvi_d8  = dvi_d[8];
+assign dvi_d9  = dvi_d[9];
+assign dvi_d10 = dvi_d[10];
+assign dvi_d11 = dvi_d[11];
+
+dvi_video_test my_dvi_video_test(
+  .CLK_P(clk),
+  .CLK_N(clk),
+  .I2C_SDA(dvi_iic_sda),
+  .I2C_SCL(dvi_iic_scl),
+
+  .DVI_D(dvi_d),
+  .DVI_H(dvi_h),
+  .DVI_V(dvi_v),
+  .DVI_DE(dvi_de),
+  .DVI_XCLK_N(dvi_xclk_n),
+  .DVI_XCLK_P(dvi_xclk_p),
+  .DVI_RESET_B(dvi_reset_b),
+
+  .VGA_PIXEL_CLK(1'b0),
+  .VGA_Y_GREEN(8'b0),
+  .VGA_CBCR_RED(8'b0),
+  .VGA_BLUE(8'b0),
+  .VGA_HSYNC(1'b0),
+  .VGA_VSYNC(1'b0),
+  .VGA_ODD_EVEN_B(1'b0),
+  .VGA_SOGOUT(1'b0),
+  .VGA_CLAMP(1'b0),
+  .VGA_COAST(1'b0),
+
+  .SOGOUT(),
+  .PIXEL_X_COORD(),
+  .PIXEL_Y_COORD(),
+  .TOTAL_PIXEL_COUNT(),
+  .VGA_DATA_VALID(),
+  .Y(),
+  .HSYNC(),
+  .VSYNC(),
+  .DVI_PIXEL_COUNT(),
+  .DVI_X_COORD(),
+  .DVI_Y_COORD(),
+  .DVI_DATA_VALID()
+
+ );
 
-== FleetSim ==============================================================
 
-== FPGA ==============================================================
 
+/*
   assign dvi_de      = 1;
   assign dvi_reset_b = 1;
 
@@ -64,31 +120,51 @@ percolate up:    gpio_led_7   1
   assign dvi_d9      = 0;
   assign dvi_d10     = 1;
   assign dvi_d11     = 0;
-
+*/
   assign gpio_led_n = 1;
   assign gpio_led_s = 0;
 
-//  assign gpio_led_0 = dvi_gpio1;
-//  assign gpio_led_1 = 0;
-//  assign gpio_led_2 = 1;
-//  assign gpio_led_3 = 0;
-//  assign gpio_led_4 = 1;
+  assign gpio_led_0 = dvi_gpio1;
+  assign gpio_led_1 = gpio_sw_c;
+  //assign gpio_led_2 = dvi_xclk_p;
+  //assign gpio_led_3 = 0;
+  //assign gpio_led_4 = 1;
   assign gpio_led_5 = 0;
   assign gpio_led_6 = 1;
   assign gpio_led_7 = 0;
-
+/*
   wire dvi_xclk_p_unbuffered;
   wire dvi_xclk_n_unbuffered;
   wire dvi_xclk_fb;
-
+*/
 /*
+  reg initialized;
+  always @(posedge clk) begin
+    if (rst) begin
+      initialized <= 0;
+    end else begin
+      if (!initialized && gpio_sw_c) begin
+      end
+    end
+  end
+*/
+/*
+i2c_video_programmer my_i2c_video_programmer
+  ( .CLK200Mhz(clk),
+    .RST(rst),
+    .I2C_SDA(dvi_iic_sda),
+    .I2C_SCL(dvi_iic_scl)
+  );
+
+
   BUFG GBUF_FOR_DVI_CLOCK_N (.I(dvi_xclk_n_unbuffered), .O(dvi_xclk_n));
   BUFG GBUF_FOR_DVI_CLOCK_P (.I(dvi_xclk_p_unbuffered), .O(dvi_xclk_p));
-  DCM  // 25Mhz VGA clock
+  DCM  // 36Mhz DVI clock
    #(
-      .CLKFX_MULTIPLY(4),
-      .CLKFX_DIVIDE(16),
-      .CLKIN_PERIOD("20 ns")
+      .CLKFX_MULTIPLY(9),
+      .CLKFX_DIVIDE(25),
+      .CLKIN_PERIOD("10 ns"),
+      .DLL_FREQUENCY_MODE("LOW")
     ) vgadcm (
       .CLKIN    (clk),
       .CLKFB    (dvi_xclk_fb),
@@ -96,7 +172,7 @@ percolate up:    gpio_led_7   1
       .CLKFX180 (dvi_xclk_n_unbuffered),
       .CLK0     (dvi_xclk_fb)
     );
-*/
+
 
   wire [31:0] vga_pixel_addr_;
   wire        vga_pixel_r;
@@ -128,8 +204,8 @@ percolate up:    gpio_led_7   1
        .fbwb_ack_i(vga_pixel_a_),
        .fbwb_dat_i(vga_pixel_data),
 
-       /* VGA signals */
-        .vga_clk(dvi_xclk),
+       // VGA signals
+        .vga_clk(dvi_xclk_p),
         .vga_psave(vga_psave),
         .vga_hsync(dvi_h),
         .vga_vsync(dvi_v),
diff --git a/src/edu/berkeley/fleet/fpga/dvi/dvi_video_test.vhd b/src/edu/berkeley/fleet/fpga/dvi/dvi_video_test.vhd
new file mode 100644 (file)
index 0000000..2dbb5de
--- /dev/null
@@ -0,0 +1,438 @@
+-- Module Name:   dvi_video_test
+-- File Description:  A 'test playground' for VGA, DVI, and i2c testing.
+-- Project:  FPGA Image Registration
+-- Target Device:  XC5VSX50T (Xilinx Virtex5 SXT)
+-- Target Board:  ML506
+-- Synthesis Tool:  Xilinx ISE 9.2
+-- Copyright (C) 2008 Brandyn Allen White
+-- Contact:  bwhite(at)cs.ucf.edu
+-- Project Website:  http://code.google.com/p/fpga-image-registration/
+
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+
+LIBRARY UNISIM;
+USE UNISIM.VComponents.ALL;
+
+ENTITY dvi_video_test IS
+  PORT (CLK_P   : IN  std_logic;
+        CLK_N   : IN  std_logic;
+        -- I2C Signals
+        I2C_SDA : OUT std_logic;
+        I2C_SCL : OUT std_logic;
+
+        -- DVI Signals
+        DVI_D       : OUT std_logic_vector (11 DOWNTO 0);
+        DVI_H       : OUT std_logic;
+        DVI_V       : OUT std_logic;
+        DVI_DE      : OUT std_logic;
+        DVI_XCLK_N  : OUT std_logic;
+        DVI_XCLK_P  : OUT std_logic;
+        DVI_RESET_B : OUT std_logic;
+
+        -- VGA Chip connections
+        VGA_PIXEL_CLK  : IN std_logic;
+        VGA_Y_GREEN    : IN std_logic_vector (7 DOWNTO 0);
+        VGA_CBCR_RED   : IN std_logic_vector (7 DOWNTO 0);
+        VGA_BLUE       : IN std_logic_vector(7 DOWNTO 0);
+        VGA_HSYNC      : IN std_logic;
+        VGA_VSYNC      : IN std_logic;
+        VGA_ODD_EVEN_B : IN std_logic;
+        VGA_SOGOUT     : IN std_logic;
+        VGA_CLAMP      : IN std_logic;
+        VGA_COAST      : IN std_logic;
+
+        -- Dummy Chipscope outputs
+        SOGOUT            : OUT std_logic;
+        PIXEL_X_COORD     : OUT std_logic_vector(9 DOWNTO 0);
+        PIXEL_Y_COORD     : OUT std_logic_vector(9 DOWNTO 0);
+        TOTAL_PIXEL_COUNT : OUT std_logic_vector(19 DOWNTO 0);
+        VGA_DATA_VALID    : OUT std_logic;
+        Y                 : OUT std_logic_vector (7 DOWNTO 0);
+        HSYNC             : OUT std_logic;
+        VSYNC             : OUT std_logic;
+        DVI_PIXEL_COUNT   : OUT std_logic_vector(19 DOWNTO 0);
+        DVI_X_COORD       : OUT std_logic_vector(9 DOWNTO 0);
+        DVI_Y_COORD       : OUT std_logic_vector(9 DOWNTO 0);
+        DVI_DATA_VALID    : OUT std_logic
+        );
+END dvi_video_test;
+
+ARCHITECTURE Behavioral OF dvi_video_test IS
+  COMPONENT vga_timing_generator IS
+                                   GENERIC (WIDTH       :     integer := 1024;
+                                            H_FP        :     integer := 24;
+                                            H_SYNC      :     integer := 136;
+                                            H_BP        :     integer := 160;
+                                            HEIGHT      :     integer := 768;
+                                            V_FP        :     integer := 3;
+                                            V_SYNC      :     integer := 6;
+                                            V_BP        :     integer := 29;
+                                            HEIGHT_BITS :     integer := 10;
+                                            WIDTH_BITS  :     integer := 10;
+                                            DATA_DELAY  :     integer := 0
+                                            );
+                                 PORT (CLK              : IN  std_logic;
+                                       RST              : IN  std_logic;
+                                       HSYNC            : OUT std_logic;
+                                       VSYNC            : OUT std_logic;
+                                       X_COORD          : OUT unsigned(WIDTH_BITS-1 DOWNTO 0);
+                                       Y_COORD          : OUT unsigned(HEIGHT_BITS-1 DOWNTO 0);
+                                       PIXEL_COUNT      : OUT unsigned(WIDTH_BITS+HEIGHT_BITS-1 DOWNTO 0);
+                                       DATA_VALID       : OUT std_logic;
+                                       DATA_VALID_EXT   : OUT std_logic);
+  END COMPONENT;
+
+  COMPONENT vga_timing_decode IS
+                                GENERIC (
+                                  HEIGHT        :     integer := 480;
+                                  WIDTH         :     integer := 640;
+                                  H_BP          :     integer := 117;
+                                  V_BP          :     integer := 34;
+                                  HEIGHT_BITS   :     integer := 10;
+                                  WIDTH_BITS    :     integer := 10;
+                                  DATA_DELAY    :     integer := 0
+                                  );
+                              PORT (CLK         : IN  std_logic;
+                                    RST         : IN  std_logic;
+                                    VSYNC       : IN  std_logic;
+                                    HSYNC       : IN  std_logic;
+                                    X_COORD     : OUT unsigned(WIDTH_BITS-1 DOWNTO 0);
+                                    Y_COORD     : OUT unsigned(HEIGHT_BITS-1 DOWNTO 0);
+                                    PIXEL_COUNT : OUT unsigned(HEIGHT_BITS+WIDTH_BITS-1 DOWNTO 0);
+                                    DATA_VALID  : OUT std_logic);
+  END COMPONENT;
+
+  COMPONENT i2c_video_programmer IS
+                                   PORT (CLK200Mhz : IN  std_logic;
+                                         RST       : IN  std_logic;
+                                         I2C_SDA   : OUT std_logic;
+                                         I2C_SCL   : OUT std_logic);
+  END COMPONENT;
+
+  SIGNAL pix_clk                                     : std_logic;  -- This is the pixel clock for the DVI output and sync generator
+  SIGNAL clk_fb, data_valid, data_valid_ext, clk_buf : std_logic;
+  SIGNAL dvi_red, dvi_green, dvi_blue, dvi_gray      : std_logic_vector(7 DOWNTO 0);  -- These hold the values for the packed RGB DVI output data
+  SIGNAL dvi_h_wire, dvi_v_wire                      : std_logic;
+  SIGNAL dvi_x_coord_wire, dvi_y_coord_wire          : unsigned(9 DOWNTO 0);
+  SIGNAL dvi_pixel_count_wire                        : unsigned(19 DOWNTO 0);
+  SIGNAL vga_x_coord_wire, vga_y_coord_wire          : unsigned(9 DOWNTO 0);
+  SIGNAL vga_pixel_count_wire                        : unsigned(19 DOWNTO 0);
+BEGIN
+
+  -----------------------------------------------------------------------------
+  -- CLK Management
+--  IBUFGDS_inst : IBUFGDS
+--    GENERIC MAP (
+--      IOSTANDARD => "DEFAULT")
+--    PORT MAP (
+--      O          => clk_buf,            -- Clock buffer output
+--      I          => CLK_P,              -- Diff_p clock buffer input
+--      IB         => CLK_N               -- Diff_n clock buffer input
+--      );
+  BUF_inst : BUF
+    PORT MAP (
+      O          => clk_buf,            -- Clock buffer output
+      I          => CLK_P               -- Diff_p clock buffer input
+      );
+
+  DCM_BASE_dvi : DCM_BASE
+    GENERIC MAP (
+      CLKDV_DIVIDE          => 4.0,     -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
+      --   7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
+      CLKFX_DIVIDE          => 16,      -- Can be any interger from 1 to 32
+      CLKFX_MULTIPLY        => 2,       -- Can be any integer from 2 to 32
+      CLKIN_DIVIDE_BY_2     => false,   -- TRUE/FALSE to enable CLKIN divide by two feature
+      CLKIN_PERIOD          => 10.0,     -- Specify period of input clock in ns from 1.25 to 1000.00
+      CLKOUT_PHASE_SHIFT    => "NONE",  -- Specify phase shift mode of NONE or FIXED
+      CLK_FEEDBACK          => "1X",    -- Specify clock feedback of NONE or 1X
+      DCM_AUTOCALIBRATION   => true,    -- DCM calibrartion circuitry TRUE/FALSE
+      DCM_PERFORMANCE_MODE  => "MAX_SPEED",  -- Can be MAX_SPEED or MAX_RANGE
+      DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",  -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
+                                        --   an integer from 0 to 15
+      DFS_FREQUENCY_MODE    => "HIGH",  -- LOW or HIGH frequency mode for frequency synthesis
+      DLL_FREQUENCY_MODE    => "LOW",  -- LOW, HIGH, or HIGH_SER frequency mode for DLL
+      DUTY_CYCLE_CORRECTION => true,    -- Duty cycle correction, TRUE or FALSE
+      FACTORY_JF            => X"F0F0",  -- FACTORY JF Values Suggested to be set to X"F0F0" 
+      PHASE_SHIFT           => 0,       -- Amount of fixed phase shift from -255 to 1023
+      STARTUP_WAIT          => false)   -- Delay configuration DONE until DCM LOCK, TRUE/FALSE
+    PORT MAP (
+      CLK0                  => clk_fb,  -- 0 degree DCM CLK ouptput
+      CLKDV                 => pix_clk,
+      CLKFB                 => clk_fb,  -- DCM clock feedback
+      CLKIN                 => clk_buf,  -- Clock input (from IBUFG, BUFG or DCM)
+      RST                   => '0'      -- DCM asynchronous reset input
+      );
+
+  -----------------------------------------------------------------------------
+  -- I2C Code
+  i2c_video_programmer_i : i2c_video_programmer
+    PORT MAP (
+      CLK200Mhz => clk_buf,
+      RST       => '0',
+      I2C_SDA   => I2C_SDA,
+      I2C_SCL   => I2C_SCL);
+
+
+  -------------------------------------------------------------------------------
+  -- DVI Code
+  DVI_DE <= data_valid_ext;
+
+  -- This is a way to generate a differential clock with low jitter (as both
+  -- edges are handled in the same way)
+  ODDR_xclk_p : ODDR
+    GENERIC MAP(
+      DDR_CLK_EDGE => "OPPOSITE_EDGE",  -- "OPPOSITE_EDGE" or "SAME_EDGE" 
+      INIT         => '0',              -- Initial value for Q port ('1' or '0')
+      SRTYPE       => "SYNC")           -- Reset Type ("ASYNC" or "SYNC")
+    PORT MAP (
+      Q            => DVI_XCLK_P,       -- 1-bit DDR output
+      C            => pix_clk,          -- 1-bit clock input
+      CE           => '1',              -- 1-bit clock enable input
+      D1           => '1',              -- 1-bit data input (positive edge)
+      D2           => '0',              -- 1-bit data input (negative edge)
+      R            => '0',              -- 1-bit reset input
+      S            => '0'               -- 1-bit set input
+      );
+  ODDR_xclk_n : ODDR
+    GENERIC MAP(
+      DDR_CLK_EDGE => "OPPOSITE_EDGE",  -- "OPPOSITE_EDGE" or "SAME_EDGE" 
+      INIT         => '0',              -- Initial value for Q port ('1' or '0')
+      SRTYPE       => "SYNC")           -- Reset Type ("ASYNC" or "SYNC")
+    PORT MAP (
+      Q            => DVI_XCLK_N,       -- 1-bit DDR output
+      C            => pix_clk,          -- 1-bit clock input
+      CE           => '1',              -- 1-bit clock enable input
+      D1           => '0',              -- 1-bit data input (positive edge)
+      D2           => '1',              -- 1-bit data input (negative edge)
+      R            => '0',              -- 1-bit reset input
+      S            => '0'               -- 1-bit set input
+      );
+
+  DVI_RESET_B      <= '1';
+  PROCESS (dvi_x_coord_wire) IS
+  BEGIN  -- PROCESS
+    IF dvi_y_coord_wire(0) = '1' THEN
+      CASE to_integer(dvi_x_coord_wire) IS
+        WHEN 1  =>
+          dvi_gray <= "11111111";
+        WHEN 2  =>
+          dvi_gray <= "00000000";
+        WHEN 5  =>
+          dvi_gray <= "11111111";
+        WHEN 6  =>
+          dvi_gray <= "11111111";
+        WHEN 7  =>
+          dvi_gray <= "00000000";
+        WHEN 8  =>
+          dvi_gray <= "00000000";
+        WHEN 12 =>
+          dvi_gray <= "11111111";
+        WHEN 13 =>
+          dvi_gray <= "11111111";
+        WHEN 14 =>
+          dvi_gray <= "11111111";
+        WHEN 15 =>
+          dvi_gray <= "00000000";
+        WHEN 16 =>
+          dvi_gray <= "00000000";
+        WHEN 17 =>
+          dvi_gray <= "00000000";
+
+        WHEN 639-1  =>
+          dvi_gray <= "11111111";
+        WHEN 639-2  =>
+          dvi_gray <= "00000000";
+        WHEN 639-5  =>
+          dvi_gray <= "11111111";
+        WHEN 639-6  =>
+          dvi_gray <= "11111111";
+        WHEN 639-7  =>
+          dvi_gray <= "00000000";
+        WHEN 639-8  =>
+          dvi_gray <= "00000000";
+        WHEN 639-12 =>
+          dvi_gray <= "11111111";
+        WHEN 639-13 =>
+          dvi_gray <= "11111111";
+        WHEN 639-14 =>
+          dvi_gray <= "11111111";
+        WHEN 639-15 =>
+          dvi_gray <= "00000000";
+        WHEN 639-16 =>
+          dvi_gray <= "00000000";
+        WHEN 639-17 =>
+          dvi_gray <= "00000000";
+        WHEN OTHERS =>
+          dvi_gray <= "01111111";
+      END CASE;
+    ELSE
+      CASE to_integer(dvi_x_coord_wire) IS
+        WHEN 1      =>
+          dvi_gray <= "00000000";
+        WHEN 2      =>
+          dvi_gray <= "11111111";
+        WHEN 5      =>
+          dvi_gray <= "00000000";
+        WHEN 6      =>
+          dvi_gray <= "00000000";
+        WHEN 7      =>
+          dvi_gray <= "11111111";
+        WHEN 8      =>
+          dvi_gray <= "11111111";
+        WHEN 12     =>
+          dvi_gray <= "00000000";
+        WHEN 13     =>
+          dvi_gray <= "00000000";
+        WHEN 14     =>
+          dvi_gray <= "00000000";
+        WHEN 15     =>
+          dvi_gray <= "11111111";
+        WHEN 16     =>
+          dvi_gray <= "11111111";
+        WHEN 17     =>
+          dvi_gray <= "11111111";
+
+        WHEN 639-1  =>
+          dvi_gray <= "00000000";
+        WHEN 639-2  =>
+          dvi_gray <= "11111111";
+        WHEN 639-5  =>
+          dvi_gray <= "00000000";
+        WHEN 639-6  =>
+          dvi_gray <= "00000000";
+        WHEN 639-7  =>
+          dvi_gray <= "11111111";
+        WHEN 639-8  =>
+          dvi_gray <= "11111111";
+        WHEN 639-12 =>
+          dvi_gray <= "00000000";
+        WHEN 639-13 =>
+          dvi_gray <= "00000000";
+        WHEN 639-14 =>
+          dvi_gray <= "00000000";
+        WHEN 639-15 =>
+          dvi_gray <= "11111111";
+        WHEN 639-16 =>
+          dvi_gray <= "11111111";
+        WHEN 639-17 =>
+          dvi_gray <= "11111111";
+        WHEN OTHERS =>
+          dvi_gray <= "01111111";
+      END CASE;
+    END IF;
+
+    dvi_red   <= dvi_gray;
+    dvi_blue  <= dvi_gray;
+    dvi_green <= dvi_gray;
+-- IF h_pixel_count < "00000000100" THEN
+-- dvi_red <= "00000000";
+-- dvi_green <= "00000000";
+-- dvi_blue <= "11111111";
+-- ELSIF h_pixel_count < "00000001000" THEN
+-- dvi_red <= "00000000";
+-- dvi_green <= "11111111";
+-- dvi_blue <= "00000000";
+-- ELSIF h_pixel_count > "01001111000" THEN
+-- dvi_red <= "11111111";
+-- dvi_green <= "00000000";
+-- dvi_blue <= "00000000";
+-- ELSE
+-- dvi_red <= "00000000";
+-- dvi_green <= "00000000";
+-- dvi_blue <= "11111111";
+-- END IF;
+  END PROCESS;
+  -- This outputs the color values in the DVI chips DDR mode, if the
+  -- dvi_reg/green/blue wires are used on the posedge of the pix_clk, then
+  -- knowledge of this DDR format isn't necessary
+  ODDR_dvi_d0  : ODDR
+    PORT MAP (DVI_D(0), pix_clk, '1', dvi_green(4), dvi_blue(0), NOT data_valid_ext, '0');
+  ODDR_dvi_d1  : ODDR
+    PORT MAP (DVI_D(1), pix_clk, '1', dvi_green(5), dvi_blue(1), NOT data_valid_ext, '0');
+  ODDR_dvi_d2  : ODDR
+    PORT MAP (DVI_D(2), pix_clk, '1', dvi_green(6), dvi_blue(2), NOT data_valid_ext, '0');
+  ODDR_dvi_d3  : ODDR
+    PORT MAP (DVI_D(3), pix_clk, '1', dvi_green(7), dvi_blue(3), NOT data_valid_ext, '0');
+  ODDR_dvi_d4  : ODDR
+    PORT MAP (DVI_D(4), pix_clk, '1', dvi_red(0), dvi_blue(4), NOT data_valid_ext, '0');
+  ODDR_dvi_d5  : ODDR
+    PORT MAP (DVI_D(5), pix_clk, '1', dvi_red(1), dvi_blue(5), NOT data_valid_ext, '0');
+  ODDR_dvi_d6  : ODDR
+    PORT MAP (DVI_D(6), pix_clk, '1', dvi_red(2), dvi_blue(6), NOT data_valid_ext, '0');
+  ODDR_dvi_d7  : ODDR
+    PORT MAP (DVI_D(7), pix_clk, '1', dvi_red(3), dvi_blue(7), NOT data_valid_ext, '0');
+  ODDR_dvi_d8  : ODDR
+    PORT MAP (DVI_D(8), pix_clk, '1', dvi_red(4), dvi_green(0), NOT data_valid_ext, '0');
+  ODDR_dvi_d9  : ODDR
+    PORT MAP (DVI_D(9), pix_clk, '1', dvi_red(5), dvi_green(1), NOT data_valid_ext, '0');
+  ODDR_dvi_d10 : ODDR
+    PORT MAP (DVI_D(10), pix_clk, '1', dvi_red(6), dvi_green(2), NOT data_valid_ext, '0');
+  ODDR_dvi_d11 : ODDR
+    PORT MAP (DVI_D(11), pix_clk, '1', dvi_red(7), dvi_green(3), NOT data_valid_ext, '0');
+
+  vga_timing_generator_i : vga_timing_generator
+    GENERIC MAP(WIDTH  => 640,
+                H_FP   => 16,
+                H_SYNC => 96,
+                H_BP   => 48,
+
+                HEIGHT     => 480,
+                V_FP       => 12,
+                V_SYNC     => 2,
+                V_BP       => 31,
+                DATA_DELAY => 0)
+
+    PORT MAP (
+      RST            => '0',
+      HSYNC          => dvi_h_wire,
+      VSYNC          => dvi_v_wire,
+      DATA_VALID     => data_valid,
+      DATA_VALID_EXT => data_valid_ext,
+      X_COORD        => dvi_x_coord_wire,
+      Y_COORD        => dvi_y_coord_wire,
+      PIXEL_COUNT    => dvi_pixel_count_wire,
+      CLK            => pix_clk);
+  DVI_DATA_VALID  <= data_valid;
+  DVI_H           <= NOT dvi_h_wire;
+  DVI_V           <= NOT dvi_v_wire;
+  DVI_X_COORD     <= std_logic_vector(dvi_x_coord_wire);
+  DVI_Y_COORD     <= std_logic_vector(dvi_y_coord_wire);
+  DVI_PIXEL_COUNT <= std_logic_vector(dvi_pixel_count_wire);
+
+  -----------------------------------------------------------------------------
+  -- VGA Input
+
+  -- Hooks to chipscope outputs
+  Y      <= VGA_Y_GREEN;
+  HSYNC  <= VGA_HSYNC;
+  VSYNC  <= VGA_VSYNC;
+  SOGOUT <= VGA_SOGOUT;
+  vga_timing_decode_i : vga_timing_decode
+    PORT MAP (
+      CLK         => VGA_PIXEL_CLK,
+      RST         => '0',
+      VSYNC       => VGA_VSYNC,
+      HSYNC       => VGA_HSYNC,
+      DATA_VALID  => VGA_DATA_VALID,
+      X_COORD     => vga_x_coord_wire,
+      Y_COORD     => vga_y_coord_wire,
+      PIXEL_COUNT => vga_pixel_count_wire);
+  PIXEL_X_COORD <= std_logic_vector(vga_x_coord_wire);
+  PIXEL_Y_COORD <= std_logic_vector(vga_y_coord_wire);
+  TOTAL_PIXEL_COUNT <= std_logic_vector(vga_pixel_count_wire);
+END Behavioral;
diff --git a/src/edu/berkeley/fleet/fpga/dvi/i2c_core.vhd b/src/edu/berkeley/fleet/fpga/dvi/i2c_core.vhd
new file mode 100644 (file)
index 0000000..b65bf86
--- /dev/null
@@ -0,0 +1,192 @@
+-- Module Name:  i2c_core.vhd
+-- File Description:  Generic i2c module with write capability only.
+-- Project:  FPGA Image Registration
+-- Target Device:  XC5VSX50T (Xilinx Virtex5 SXT)
+-- Target Board:  ML506
+-- Synthesis Tool:  Xilinx ISE 9.2
+-- Copyright (C) 2008 Brandyn Allen White
+-- Contact:  bwhite(at)cs.ucf.edu
+-- Project Website:  http://code.google.com/p/fpga-image-registration/
+
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+-- NOTE The data is in little endian byte ordering, data is sent lowest byte
+-- first, highest bit first (I2C convention).
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.STD_LOGIC_ARITH.ALL;
+USE IEEE.STD_LOGIC_UNSIGNED.ALL;
+
+
+ENTITY i2c_core IS
+  PORT (clk           : IN  std_logic;
+        data          : IN  std_logic_vector (23 DOWNTO 0);
+        new_data      : IN  std_logic;
+        reset         : IN  std_logic;
+        i2c_sda       : OUT std_logic;
+        i2c_scl       : OUT std_logic;
+        received_data : OUT std_logic);
+END i2c_core;
+
+ARCHITECTURE Behavioral OF i2c_core IS
+  SIGNAL cur_data          : std_logic_vector (23 DOWNTO 0);  -- {device_id(7 downto 0), address(7 downto 0), data(7 downto 0)}
+  SIGNAL i2c_state         : std_logic_vector (2 DOWNTO 0) := (OTHERS => '0');  -- {START, DATA, POST_DATA, STOP, STOP_WAIT, X, X, X}
+  SIGNAL byte_position     : std_logic_vector(1 DOWNTO 0)  := (OTHERS => '0');  -- {device_id, address, data, X}
+  SIGNAL bit_position      : std_logic_vector(2 DOWNTO 0)  := (OTHERS => '0');
+  SIGNAL received_data_reg : std_logic                     := '0';
+  SIGNAL i2c_sda_reg       : std_logic                     := '1';
+
+-- I2C Clock Variables
+  SIGNAL i2c_clock_counter    : std_logic_vector (8 DOWNTO 0) := (OTHERS => '0');  -- [0,499]
+  SIGNAL i2c_edge_count       : std_logic_vector (2 DOWNTO 0) := (OTHERS => '0');  -- [0,4]
+  SIGNAL i2c_clock            : std_logic                     := '1';
+  SIGNAL i2c_clock_5x         : std_logic                     := '1';
+  SIGNAL i2c_clock_5x_posedge : std_logic                     := '1';
+
+BEGIN
+  i2c_scl       <= '0' WHEN i2c_clock = '0'   ELSE 'Z';  -- Output using {0,Z logic}
+  i2c_sda       <= '0' WHEN i2c_sda_reg = '0' ELSE 'Z';  -- Output using {0,Z logic}
+  received_data <= received_data_reg;
+
+  PROCESS(clk)
+  BEGIN
+    IF (clk'event AND clk = '1') THEN
+      -- Set initial register values upon synchronous reset
+      IF (reset = '1') THEN
+        i2c_state         <= (OTHERS => '0');
+        byte_position     <= (OTHERS => '0');
+        bit_position      <= (OTHERS => '0');
+        received_data_reg <= '0';
+        i2c_sda_reg       <= '1';
+
+        -- I2C Clock Variables
+        i2c_clock_counter    <= (OTHERS => '0');
+        i2c_edge_count       <= (OTHERS => '0');
+        i2c_clock            <= '1';
+        i2c_clock_5x         <= '1';
+        i2c_clock_5x_posedge <= '1';
+      ELSE
+        -- If we are supposed to start; however, no data is ready, then reset the clock logic to hold it high
+        IF (i2c_state = "000" AND new_data = '0') THEN
+          i2c_sda_reg       <= '1';
+          received_data_reg <= '0';
+
+                                        -- I2C Clock Variables
+          i2c_clock_counter    <= (OTHERS => '0');
+          i2c_edge_count       <= (OTHERS => '0');
+          i2c_clock            <= '1';
+          i2c_clock_5x         <= '1';
+          i2c_clock_5x_posedge <= '1';
+        ELSE
+                                        -- I2C Clock generation - Reduces clock rate by 100 for internal use and 500 for external use.
+          IF (i2c_clock_counter = 99 OR i2c_clock_counter = 199 OR i2c_clock_counter = 299 OR i2c_clock_counter = 399 OR i2c_clock_counter = 499) THEN
+            i2c_clock_5x <= NOT i2c_clock_5x;
+            IF (i2c_clock_5x = '0') THEN
+              i2c_clock_5x_posedge <= '1';
+              IF (i2c_edge_count < 4) THEN
+                i2c_edge_count <= i2c_edge_count + 1;
+              ELSE
+                i2c_edge_count <= (OTHERS => '0');
+              END IF;
+            END IF;
+          END IF;
+
+                                        -- Toggle the external I2C clock every 500 ticks
+          IF (i2c_clock_counter = 499) THEN
+            i2c_clock_counter <= (OTHERS => '0');
+            i2c_clock         <= NOT i2c_clock;
+          ELSE
+            i2c_clock_counter <= i2c_clock_counter + 1;
+          END IF;
+        END IF;
+
+        -- Main I2C Logic
+        IF (i2c_clock_5x_posedge = '1') THEN
+          i2c_clock_5x_posedge <= '0';
+          CASE i2c_edge_count IS  -- Edge selection -> individual state selection
+            WHEN "001" =>
+              IF (i2c_state = "011") THEN      -- STATE: stop
+                i2c_sda_reg <= '1';
+                i2c_state   <= "000";   -- 'start'
+              END IF;
+            WHEN "010" =>
+              IF (i2c_state = "000") THEN      -- STATE: start
+                IF (new_data = '1' AND received_data_reg = '0') THEN
+                  i2c_sda_reg       <= '0';
+                  cur_data          <= data;
+                  received_data_reg <= '1';
+                  i2c_state         <= "001";  -- 'data'
+                END IF;
+              END IF;
+
+            WHEN "100" =>
+              CASE i2c_state IS
+                WHEN "001" =>           -- STATE: data
+                  CASE bit_position IS  -- Select bit position and output it (NOTE:  MSB is output first!), TODO investigate other bit selection methods
+                    WHEN "000" =>
+                      i2c_sda_reg <= cur_data(7);
+                    WHEN "001" =>
+                      i2c_sda_reg <= cur_data(6);
+                    WHEN "010" =>
+                      i2c_sda_reg <= cur_data(5);
+                    WHEN "011" =>
+                      i2c_sda_reg <= cur_data(4);
+                    WHEN "100" =>
+                      i2c_sda_reg <= cur_data(3);
+                    WHEN "101" =>
+                      i2c_sda_reg <= cur_data(2);
+                    WHEN "110" =>
+                      i2c_sda_reg <= cur_data(1);
+                    WHEN "111" =>
+                      i2c_sda_reg <= cur_data(0);
+                    WHEN OTHERS =>
+                      NULL;
+                  END CASE;
+                      bit_position <= bit_position + 1;
+                      IF (bit_position = "111") THEN
+                        i2c_state <= "010";  -- 'post_data'
+                      ELSE
+                        i2c_state <= "001";  -- 'data'
+                      END IF;
+                WHEN "010" =>           -- STATE: post_data
+                  cur_data(15 DOWNTO 0) <= cur_data(23 DOWNTO 8);  -- Shift right by 8, TODO investigate other shifting methods
+                  i2c_sda_reg           <= '1';
+                  IF (byte_position = 2) THEN
+                    byte_position <= (OTHERS => '0');
+                    i2c_state     <= "100";
+                  ELSE
+                    byte_position <= byte_position + 1;
+                    i2c_state     <= "001";
+                  END IF;
+                WHEN "100" =>           -- STATE: stop_wait
+                  i2c_sda_reg <= '0';
+                  i2c_state   <= "011";      -- 'stop'
+                WHEN OTHERS =>
+                  NULL;
+              END CASE;
+            WHEN OTHERS =>
+              NULL;
+          END CASE;
+        END IF;
+
+        -- Data synchronization acknowledgement
+        IF (new_data = '0' AND received_data_reg = '1') THEN
+          received_data_reg <= '0';
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+END Behavioral;
+
diff --git a/src/edu/berkeley/fleet/fpga/dvi/i2c_video_programmer.vhd b/src/edu/berkeley/fleet/fpga/dvi/i2c_video_programmer.vhd
new file mode 100644 (file)
index 0000000..817daeb
--- /dev/null
@@ -0,0 +1,159 @@
+-- Module Name:  i2c_video_programmer
+-- File Description:  Uses the I2C module to program the CH7301C and AD9980.
+-- Project:  FPGA Image Registration
+-- Target Device:  XC5VSX50T (Xilinx Virtex5 SXT)
+-- Target Board:  ML506
+-- Synthesis Tool:  Xilinx ISE 9.2
+-- Copyright (C) 2008 Brandyn Allen White
+-- Contact:  bwhite(at)cs.ucf.edu
+-- Project Website:  http://code.google.com/p/fpga-image-registration/
+
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+LIBRARY UNISIM;
+USE UNISIM.VComponents.ALL;
+
+ENTITY i2c_video_programmer IS
+  PORT (CLK200Mhz : IN  std_logic;
+        RST       : IN  std_logic;
+        I2C_SDA   : OUT std_logic;
+        I2C_SCL   : OUT std_logic);
+END i2c_video_programmer;
+
+ARCHITECTURE Behavioral OF i2c_video_programmer IS
+  COMPONENT i2c_core IS
+                       PORT (clk                : IN  std_logic;
+                             data               : IN  std_logic_vector (23 DOWNTO 0);
+                             new_data           : IN  std_logic;
+                             reset              : IN  std_logic;
+                             i2c_sda            : OUT std_logic;
+                             i2c_scl            : OUT std_logic;
+                             received_data      : OUT std_logic);
+  END COMPONENT;
+  COMPONENT vga_timing_decode IS
+                                PORT (PIXEL_CLK : IN  std_logic;
+                                      VSYNC     : IN  std_logic;
+                                      HSYNC     : IN  std_logic;
+                                      HCOUNT    : OUT std_logic_vector(9 DOWNTO 0);
+                                      VCOUNT    : OUT std_logic_vector(9 DOWNTO 0));
+  END COMPONENT;
+
+
+  SIGNAL received_data : std_logic;
+  SIGNAL new_data      : std_logic            := '0';
+  SIGNAL data_count    : unsigned(3 DOWNTO 0) := (OTHERS => '0');  -- Used to count the data
+  SIGNAL i2c_data      : std_logic_vector(23 DOWNTO 0);
+                                        -- bytes sent over I2C
+  SIGNAL i2c_clk       : std_logic;     -- 50Mhz i2c module input clock
+  SIGNAL i2c_dcm_fb    : std_logic;
+BEGIN
+  PROCESS (data_count) IS
+  BEGIN  -- PROCESS
+    CASE data_count IS
+      -- START VGA IN I2C Codes
+      WHEN "0000"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#320198#, 24));
+      WHEN "0001"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#000298#, 24));
+      WHEN "0010"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#600398#, 24));
+        -- END VGA IN I2C Codes
+        -- START DVI OUT I2C Codes
+      WHEN "0011"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#C049EC#, 24));
+      WHEN "0100"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#0921EC#, 24));
+      WHEN "0101"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#0833EC#, 24));
+      WHEN "0110"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#1634EC#, 24));
+      WHEN "0111"                                        =>
+        i2c_data <= std_logic_vector(to_unsigned(16#6036EC#, 24));
+        -- END DVI OUT I2C Codes
+      WHEN OTHERS                                        =>
+        i2c_data <= (OTHERS                              => '0');
+
+    END CASE;
+  END PROCESS;
+
+  -- DCM to divide input clock (200 mhz) by 16 to produce a 12.5 Mhz I2C Input
+  -- clock (which will be divided by 500 for the SCL clock and 100 for the
+  -- internal clock)
+  -- controller input
+  DCM_BASE_i2c : DCM_BASE
+    GENERIC MAP (
+      CLKDV_DIVIDE          => 8.0,    -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5  -- used to be 16
+      --   7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
+      CLKFX_DIVIDE          => 16,      -- Can be any interger from 1 to 32 -- USED TO BE "32"!!!
+      CLKFX_MULTIPLY        => 2,       -- Can be any integer from 2 to 32 
+      CLKIN_DIVIDE_BY_2     => false,   -- TRUE/FALSE to enable CLKIN divide by two feature
+      CLKIN_PERIOD          => 10.0,     -- Specify period of input clock in ns from 1.25 to 1000.00
+      CLKOUT_PHASE_SHIFT    => "NONE",  -- Specify phase shift mode of NONE or FIXED
+      CLK_FEEDBACK          => "1X",    -- Specify clock feedback of NONE or 1X
+      DCM_AUTOCALIBRATION   => true,    -- DCM calibrartion circuitry TRUE/FALSE
+      DCM_PERFORMANCE_MODE  => "MAX_SPEED",  -- Can be MAX_SPEED or MAX_RANGE
+      DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",  -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
+                                        --   an integer from 0 to 15
+--     DFS_FREQUENCY_MODE    => "HIGH",  -- LOW or HIGH frequency mode for frequency synthesis
+      DLL_FREQUENCY_MODE    => "LOW",  -- LOW, HIGH, or HIGH_SER frequency mode for DLL
+      DUTY_CYCLE_CORRECTION => true,    -- Duty cycle correction, TRUE or FALSE
+      FACTORY_JF            => X"F0F0",  -- FACTORY JF Values Suggested to be set to X"F0F0" 
+      PHASE_SHIFT           => 0,       -- Amount of fixed phase shift from -255 to 1023
+      STARTUP_WAIT          => false)   -- Delay configuration DONE until DCM LOCK, TRUE/FALSE
+    PORT MAP (
+      CLK0                  => i2c_dcm_fb,  -- 0 degree DCM CLK ouptput
+      CLKDV                 => i2c_clk,
+      CLKFB                 => i2c_dcm_fb,  -- DCM clock feedback
+      CLKIN                 => CLK200Mhz,  -- Clock input (from IBUFG, BUFG or DCM)
+      RST                   => '0'      -- DCM asynchronous reset input
+      );
+
+
+  -- purpose: This controls the data handshake with the I2C module, and manages the data to be sent
+  -- type   : sequential
+  -- inputs : CLK, RST, new_data
+  -- outputs: received_data
+  PROCESS (i2c_clk) IS
+  BEGIN  -- PROCESS
+    IF i2c_clk'event AND i2c_clk = '1' THEN  -- rising clock edge
+      IF new_data = '0' AND received_data = '0' THEN
+        new_data <= '1';
+      END IF;
+
+      IF new_data = '1' AND received_data = '1' THEN
+        new_data     <= '0';
+        IF data_count < 7 THEN          -- Prevents overflow
+          data_count <= data_count + 1;
+        ELSE
+          data_count <= (OTHERS => '0');
+        END IF;
+      END IF; END IF;
+    END PROCESS;
+
+      i2c_core_i : i2c_core
+        PORT MAP (
+          CLK           => i2c_clk,
+          data          => i2c_data,
+          new_data      => new_data,
+          reset         => '0',
+          i2c_sda       => I2C_SDA,
+          i2c_scl       => I2C_SCL,
+          received_data => received_data);
+
+
+    END Behavioral;
+
diff --git a/src/edu/berkeley/fleet/fpga/dvi/vga_timing_decode.vhd b/src/edu/berkeley/fleet/fpga/dvi/vga_timing_decode.vhd
new file mode 100644 (file)
index 0000000..22914da
--- /dev/null
@@ -0,0 +1,144 @@
+-- Module Name:  vga_timing_decode.vhd
+-- File Description:  Takes in VGA timing signals, outputs pixel oriented
+-- signals. Valid output starts at the beginning of the next valid frame.
+-- Project:  FPGA Image Registration
+-- Target Device:  XC5VSX50T (Xilinx Virtex5 SXT)
+-- Target Board:  ML506
+-- Synthesis Tool:  Xilinx ISE 9.2
+-- Copyright (C) 2008 Brandyn Allen White
+-- Contact:  bwhite(at)cs.ucf.edu
+-- Project Website:  http://code.google.com/p/fpga-image-registration/
+
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+
+ENTITY vga_timing_decode IS
+  GENERIC (
+    HEIGHT      : integer := 480;
+    WIDTH       : integer := 640;
+    H_BP        : integer := 117;
+    V_BP        : integer := 34;
+    HEIGHT_BITS : integer := 10;
+    WIDTH_BITS  : integer := 10;
+    HCOUNT_BITS : integer := 11;
+    VCOUNT_BITS : integer := 11;
+    DATA_DELAY  : integer := 0
+    );
+  PORT (CLK         : IN  std_logic;
+        RST         : IN  std_logic;
+        HSYNC       : IN  std_logic;
+        VSYNC       : IN  std_logic;
+        X_COORD     : OUT unsigned(WIDTH_BITS-1 DOWNTO 0);
+        Y_COORD     : OUT unsigned(HEIGHT_BITS-1 DOWNTO 0);
+        PIXEL_COUNT : OUT unsigned(HEIGHT_BITS+WIDTH_BITS-1 DOWNTO 0);
+        DATA_VALID  : OUT std_logic;
+        DONE        : OUT std_logic);
+END vga_timing_decode;
+
+ARCHITECTURE Behavioral OF vga_timing_decode IS
+  SIGNAL hcount                   : unsigned(HCOUNT_BITS-1 DOWNTO 0)            := (OTHERS => '0');
+  SIGNAL vcount                   : unsigned(VCOUNT_BITS-1 DOWNTO 0)            := (OTHERS => '0');
+  SIGNAL pixel_count_reg          : unsigned(HEIGHT_BITS+WIDTH_BITS-1 DOWNTO 0) := (OTHERS => '0');
+  SIGNAL x_coord_reg              : unsigned(WIDTH_BITS-1 DOWNTO 0)             := (OTHERS => '0');
+  SIGNAL y_coord_reg              : unsigned(HEIGHT_BITS-1 DOWNTO 0)            := (OTHERS => '0');
+  SIGNAL prev_hsync, prev_vsync   : std_logic                                   := '0';
+  SIGNAL data_valid_reg           : std_logic                                   := '0';
+  SIGNAL vsync_asserted, done_reg : std_logic                                   := '0';  -- Used to ensure that we only signal the output as valid when we have started from the beginning of a frame
+BEGIN
+  X_COORD     <= x_coord_reg;
+  Y_COORD     <= y_coord_reg;
+  PIXEL_COUNT <= pixel_count_reg;
+  -- Output data as valid only starting at the first full frame we receive
+  DATA_VALID  <= data_valid_reg WHEN vsync_asserted = '1' ELSE '0';
+  DONE        <= done_reg;
+  PROCESS (CLK) IS
+  BEGIN  -- PROCESS 
+    IF CLK'event AND CLK = '1' THEN
+      IF RST = '1' THEN
+        hcount          <= (OTHERS => '0');
+        vcount          <= (OTHERS => '0');
+        pixel_count_reg <= (OTHERS => '0');
+        x_coord_reg     <= (OTHERS => '0');
+        y_coord_reg     <= (OTHERS => '0');
+        prev_hsync      <= '0';
+        data_valid_reg  <= '0';
+        vsync_asserted  <= '0';
+        done_reg        <= '0';
+      ELSE
+        prev_hsync <= HSYNC;
+        prev_vsync <= VSYNC;
+        -----------------------------------------------------------------------
+        -- Zones w.r.t. hcount
+        -- 0<=X<H_BP-1                  -       Back Porch of H
+        -- H_BP-1=<X<H_BP+WIDTH-1       -       Active horizontal data
+        -- H_BP+WIDTH-1<=X              -       Front Porch/HSYNC
+
+        -- The backporch -1 is due to the register delay
+        IF HSYNC = '0' AND VSYNC = '0' AND hcount >= H_BP-DATA_DELAY-1 AND hcount < H_BP+WIDTH-DATA_DELAY-1 AND vcount >= V_BP AND vcount < V_BP+HEIGHT THEN    
+          IF vsync_asserted='1' THEN
+            data_valid_reg <= '1';
+          END IF;
+
+          IF data_valid_reg = '1' THEN  -- This makes the first valid pixel 0,
+                                        -- instead of 1
+            x_coord_reg <= x_coord_reg + 1;
+          END IF;
+
+          -- This makes the first valid pixel 0, and properly increments the
+          -- first pixels of every other line
+          IF (data_valid_reg = '1' AND vcount = V_BP) OR vcount > V_BP THEN
+            pixel_count_reg <= pixel_count_reg + 1;
+          END IF;
+        ELSE
+          data_valid_reg <= '0';
+          x_coord_reg    <= (OTHERS => '0');
+        END IF;
+
+        IF VSYNC = '0' THEN
+          IF HSYNC = '1' AND prev_hsync = '0' AND vcount >= V_BP AND vcount < V_BP+HEIGHT-1 THEN
+            y_coord_reg <= y_coord_reg + 1;
+          END IF;
+        ELSE          -- End of Frame
+          vcount          <= (OTHERS => '0');
+          pixel_count_reg <= (OTHERS => '0');
+          y_coord_reg     <= (OTHERS => '0');
+          vsync_asserted  <= '1';
+          -- We are done when we have been in the VSYNC='1' region previously,
+          -- and the last CT we were in the VSYNC='0' region, which means we
+          -- have been through all of the coordinates.  It will be high for one
+          -- CT, then reset to 0.
+          -- NOTE: This assumes that the VSYNC level has no glitches
+          -- NOTE: Done will be high for one CT every full frame processed
+          IF prev_vsync = '0' AND vsync_asserted = '1' THEN
+            done_reg <= '1';
+          ELSE
+            done_reg <= '0';
+          END IF;     
+        END IF;
+
+        IF HSYNC = '0' THEN
+          hcount <= hcount + 1;
+        ELSE
+          hcount <= (OTHERS => '0');
+          IF prev_hsync = '0' THEN
+            vcount <= vcount + 1;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+END Behavioral;
diff --git a/src/edu/berkeley/fleet/fpga/dvi/vga_timing_generator.vhd b/src/edu/berkeley/fleet/fpga/dvi/vga_timing_generator.vhd
new file mode 100644 (file)
index 0000000..d4fcb84
--- /dev/null
@@ -0,0 +1,154 @@
+-- Module Name:  vga_timing_generator.vhd
+-- File Description:  Generates VGA timing signals.
+-- Project:  FPGA Image Registration
+-- Target Device:  XC5VSX50T (Xilinx Virtex5 SXT)
+-- Target Board:  ML506
+-- Synthesis Tool:  Xilinx ISE 9.2
+-- Copyright (C) 2008 Brandyn Allen White
+-- Contact:  bwhite(at)cs.ucf.edu
+-- Project Website:  http://code.google.com/p/fpga-image-registration/
+
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+
+
+ENTITY vga_timing_generator IS
+  GENERIC (WIDTH       : integer := 1024;
+           H_FP        : integer := 24;
+           H_SYNC      : integer := 136;
+           H_BP        : integer := 160;
+           HEIGHT      : integer := 768;
+           V_FP        : integer := 3;
+           V_SYNC      : integer := 6;
+           V_BP        : integer := 29;
+           HEIGHT_BITS : integer := 10;
+           WIDTH_BITS  : integer := 10;
+           HCOUNT_BITS : integer := 11;
+           VCOUNT_BITS : integer := 11;
+           DATA_DELAY  : integer := 0
+
+
+           );
+  PORT (CLK            : IN  std_logic;
+        RST            : IN  std_logic;
+        HSYNC          : OUT std_logic;
+        VSYNC          : OUT std_logic;
+        X_COORD        : OUT std_logic_vector(WIDTH_BITS-1 DOWNTO 0);
+        Y_COORD        : OUT std_logic_vector(HEIGHT_BITS-1 DOWNTO 0);
+        PIXEL_COUNT    : OUT std_logic_vector(WIDTH_BITS+HEIGHT_BITS-1 DOWNTO 0);
+        DATA_VALID     : OUT std_logic;
+        DATA_VALID_EXT : OUT std_logic);
+END vga_timing_generator;
+
+ARCHITECTURE Behavioral OF vga_timing_generator IS
+  CONSTANT H_TOTAL                  : integer                                     := WIDTH+H_FP+H_SYNC+H_BP;
+  CONSTANT V_TOTAL                  : integer                                     := HEIGHT+V_FP+V_SYNC+V_BP;
+  -- bit more than specified to cover the H_FP
+  SIGNAL   hcount                   : unsigned(HCOUNT_BITS-1 DOWNTO 0)            := (OTHERS => '0');
+  SIGNAL   vcount                   : unsigned(VCOUNT_BITS-1 DOWNTO 0)            := (OTHERS => '0');
+  SIGNAL   vsync_reg, hsync_reg     : std_logic                                   := '0';  -- NOTE These are active high signals
+  SIGNAL   pixel_count_reg          : unsigned(WIDTH_BITS+HEIGHT_BITS-1 DOWNTO 0) := (OTHERS => '0');  -- This is used to keep track of the number of valid pixels that have been output this frame.  Used to allow pixel selection to be made based on 1D memory addresses.
+  SIGNAL   x_coord_reg              : unsigned(WIDTH_BITS-1 DOWNTO 0)             := (OTHERS => '0');
+  SIGNAL   y_coord_reg              : unsigned(HEIGHT_BITS-1 DOWNTO 0)            := (OTHERS => '0');
+  SIGNAL   data_valid_reg           : std_logic                                   := '0';
+BEGIN
+  HSYNC       <= hsync_reg;
+  VSYNC       <= vsync_reg;
+  X_COORD     <= std_logic_vector(x_coord_reg);
+  Y_COORD     <= std_logic_vector(y_coord_reg);
+  PIXEL_COUNT <= std_logic_vector(pixel_count_reg);
+  DATA_VALID  <= data_valid_reg;
+  PROCESS(CLK)
+  BEGIN
+    -----------------------------------------------------------------------
+    -- Zones w.r.t. hcount
+    -- 0<=X<H_BP-1                        -  Back Porch of H
+    -- H_BP-1=<X<H_BP+WIDTH-1             -  Active horizontal data
+    -- H_BP+WIDTH-1<=X<WIDTH+H_FP+H_BP-1  -  Front Porch/HSYNC
+    -- WIDTH+H_FP+H_BP-1<=X<H_TOTAL-1     -  HSYNC
+
+    -- Horizontal Pixel Count
+    IF (CLK'event AND CLK = '1') THEN
+      IF (RST = '1') THEN
+        vcount          <= (OTHERS => '0');
+        hcount          <= (OTHERS => '0');
+        hsync_reg       <= '0';
+        vsync_reg       <= '0';
+        pixel_count_reg <= (OTHERS => '0');
+        x_coord_reg     <= (OTHERS => '0');
+        y_coord_reg     <= (OTHERS => '0');
+      ELSE
+        -- Data valid signal - This is corrected for the data delay by doing
+        -- everything early by DATA_DELAY CTs.
+        IF (H_BP-DATA_DELAY-1 <= hcount AND hcount < WIDTH+H_BP-DATA_DELAY-1 AND V_BP <= vcount AND vcount < HEIGHT+V_BP) THEN
+          data_valid_reg <= '1';
+          IF data_valid_reg = '1' THEN
+            x_coord_reg <= x_coord_reg + 1;
+          END IF;
+          IF (data_valid_reg = '1' AND vcount = V_BP) OR vcount > V_BP THEN
+            pixel_count_reg <= pixel_count_reg + 1;
+          END IF;
+        ELSE
+          x_coord_reg    <= (OTHERS => '0');
+          data_valid_reg <= '0';
+        END IF;
+
+        -- Data valid external signal (to be in line with HSYNC/VSYNC)
+        IF (H_BP-1 <= hcount AND hcount < WIDTH+H_BP-1 AND V_BP <= vcount AND vcount < HEIGHT+V_BP) THEN
+          DATA_VALID_EXT <= '1';
+        ELSE
+          DATA_VALID_EXT <= '0';
+        END IF;
+
+        -- Horizontal Line Counter
+        IF hcount = (H_TOTAL-1) THEN    -- Reset hcount
+          hcount <= (OTHERS => '0');
+        ELSE
+          hcount <= hcount + 1;
+        END IF;
+
+        -- Vertical Line Counter
+        IF hcount = (H_TOTAL - 1) AND (vcount = (V_TOTAL - 1)) THEN  -- Reset
+                                                                     -- vcount
+          vcount          <= (OTHERS => '0');
+          pixel_count_reg <= (OTHERS => '0');
+          y_coord_reg     <= (OTHERS => '0');
+        ELSIF hcount = (H_TOTAL - 1) THEN
+          vcount  <= vcount + 1;
+          IF V_BP <= vcount AND vcount < HEIGHT+V_BP-1 THEN
+            y_coord_reg <= y_coord_reg + 1;
+          END IF;
+        END IF;
+
+        -- Horizontal Sync Pulse
+        IF hcount = (WIDTH+H_FP+H_BP-1) THEN
+          hsync_reg <= '1';
+        ELSIF hcount = (H_TOTAL-1) THEN
+          hsync_reg <= '0';
+        END IF;
+
+        -- Vertical Sync Pulse
+        IF hcount = (H_TOTAL-1) AND vcount = (HEIGHT+V_FP+V_BP-1) THEN
+          vsync_reg <= '1';
+        ELSIF hcount = (H_TOTAL-1) AND vcount = (V_TOTAL-1) THEN
+          vsync_reg <= '0';
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+END Behavioral;
+