OpenCores
URL https://opencores.org/ocsvn/mpeg2fpga/mpeg2fpga/trunk

Subversion Repositories mpeg2fpga

[/] [mpeg2fpga/] [trunk/] [rtl/] [mpeg2/] [mem_addr.v] - Rev 2

Compare with Previous | Blame | View Log

/*
 * mem_addr.v
 *
 * Copyright (c) 2007 Koen De Vleeschauwer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
 
/*
 * Memory address generation.
 */
 
`include "timescale.v"
 
`undef DEBUG
//`define DEBUG 1
 
 /*
  Calculates resulting memory address. Assumes 4:2:0 format. Coordinate origin is at top left.
  x axis is from left to right; y axis is from top to bottom.
 
    +------> x
    |
    |
    |
    v y
 
  - mv_x and mv_y are signed quantities, and will be scaled by 2 if chrominance addresses are computed.
  - delta_x and delta_y are unsigned, and will not be scaled if chrominance addresses are computed.
  - field_in_frame is asserted if a coordinates of a field-encoded frame picture are to be computed.
 
  Output:
  - address of 8-pixel 64-bit word.
  - offset_x: offset in bytes into the 8-pixel 64-bit word.
    If offset_x is 0, pixel is the leftmost byte of the 64-bit word. If offset_x is 7, pixel is the rightmost byte in the 64-bit word.
  - halfpixel_x: if set, horizontal halfpixel interpolation is needed.
  - halfpixel_y: if set, vertical halfpixel interpolation is needed.
  */
 
  /*
   * Note: par. 7.6.3.8, Semantic restrictions concerning predictions: (restricted slice structure)
   * "it is a restriction on the bitstream that reconstructed motion vectors shall not
   * refer to samples outside the boundary of the coded picture."
   */
 
module memory_address (
  clk, clk_en, rst,
  frame, frame_picture, field_in_frame, field, component, mb_width, horizontal_size, vertical_size,  macroblock_address, delta_x, delta_y, mv_x, mv_y, dta_in, valid_in,
  address, offset_x, halfpixel_x, halfpixel_y, dta_out, valid_out
  );
 
parameter dta_width=64;                        // dta_in, dta_out width
 
  input              clk;                      // clock
  input              clk_en;                   // clock enable
  input              rst;                      // synchronous active low reset
  input         [2:0]frame;                    // e.g. forward_reference_frame, backward_reference_frame, aux_frame, current_frame.
  input              frame_picture;            // assert if frame picture.
  input              field_in_frame;           // assert if accessing a field within a frame picture.
  input              field;                    // field number; 0 is top field, 1 is bottom field. Used in field pictures, or when accessing a field within a frame picture.
  input         [1:0]component;                // Luminance or chrominance. One of COMP_Y, COMP_CR, COMP_CB.
  input         [7:0]mb_width;                 // par. 6.3.3. width of the encoded luminance component of pictures in macroblocks
  input        [13:0]horizontal_size;          // par. 6.3.3. width of the displayable part of the luminance component of pictures in samples.
  input        [13:0]vertical_size;            // par. 6.3.3. height of the displayable part of the luminance component of the frame in lines.
  input        [12:0]macroblock_address;       // absolute position of the current macroblock. top-left macroblock has macroblock_address zero.
  input signed [12:0]delta_x;                  // horizontal offset, positive, in pixels.
  input signed [12:0]delta_y;                  // vertical offset, positive, in pixels.
  input signed [12:0]mv_x;                     // motion vector, horizontal component, signed, in halfpixels.
  input signed [12:0]mv_y;                     // motion vector, horizontal component, signed, in halfpixels.
  input [dta_width-1:0]dta_in;                 // data in
  input              valid_in;
 
  output reg   [21:0]address;                  // memory address of the 8-pixel block row.
  output reg    [2:0]offset_x;                 // Determines pixel offset within the 8-pixel block row. 0..7, 0 = leftmost pixel, msb; 7 = rightmost pixel, lsb.
  output reg         halfpixel_x;              // horizontal halfpixel offset. least significant bit of mv_x.
  output reg         halfpixel_y;              // vertical halfpixel offset. least significant bit of mv_x.
  output reg [dta_width-1:0]dta_out;           // data out is dta_in delayed so as to balance the delay in calculating address
  output reg         valid_out;
 
`include "vld_codes.v"
`include "mem_codes.v"
 
  /*
   * stage 0
   * - calculate macroblock (x, y) coordinates
   * - scale motion vectors
   */
 
  reg           [2:0]frame_0;
  reg                frame_picture_0;
  reg                field_in_frame_0;
  reg                field_0;
  reg           [1:0]component_0;
  reg           [7:0]mb_width_0;
  reg          [13:0]horizontal_size_0;
  reg          [13:0]vertical_size_0;
  reg signed   [12:0]delta_x_0;
  reg signed   [12:0]delta_y_0;
  reg signed   [12:0]mv_x_0;
  reg signed   [12:0]mv_y_0;
  reg signed   [12:0]mv_x_corr_0;
  reg signed   [12:0]mv_y_corr_0;
  reg           [7:0]macroblock_x_0; // current x-position, in macroblocks
  reg           [7:0]macroblock_y_0; // current y-position, in macroblocks
  reg [dta_width-1:0]dta_0;
  reg                valid_0;
  reg                error_0;
 
  /*
   * Macroblock (x, y) coordinate calculation assumes macroblock address
   * - starts at zero
   * - either stays the same, increments by one or is reset to zero.
   * Other combinations - eg. incrementing by two - are in error.
   */
 
  reg          [12:0]previous_macroblock_address;
 
  always @(posedge clk)
    if (~rst) previous_macroblock_address <= 13'd0;
    else if (clk_en) previous_macroblock_address <= macroblock_address;
    else previous_macroblock_address <= previous_macroblock_address;
 
  always @(posedge clk)
    if (~rst)
      begin
        macroblock_x_0 <= 8'd0;
        macroblock_y_0 <= 8'd0;
        error_0        <= 1'b1; // macroblock coordinates are unknown at reset
      end
    else if (clk_en && (macroblock_address == 13'd0))
      begin
        macroblock_x_0 <= 8'd0;
        macroblock_y_0 <= 8'd0;
        error_0        <= 1'b0; // coordinates of macroblock 0 are known
      end
    else if (clk_en && (macroblock_address == previous_macroblock_address))
      begin
        macroblock_x_0 <= macroblock_x_0;
        macroblock_y_0 <= macroblock_y_0;
        error_0        <= error_0;
      end
    else if (clk_en && (macroblock_address == (previous_macroblock_address + 13'd1)) && ((macroblock_x_0 + 8'd1) == mb_width))
      begin
        macroblock_x_0 <= 8'd0;
        macroblock_y_0 <= macroblock_y_0 + 8'd1;
        error_0        <= error_0;
      end
    else if (clk_en && (macroblock_address == (previous_macroblock_address + 13'd1)))
      begin
        macroblock_x_0 <= macroblock_x_0 + 8'd1;
        macroblock_y_0 <= macroblock_y_0;
        error_0        <= error_0;
      end
    else if (clk_en) // neither resets, nor stays the same, nor increments by one: assert error
      begin
        macroblock_x_0 <= macroblock_x_0;
        macroblock_y_0 <= macroblock_y_0;
        error_0        <= 1'b1;
      end
    else
      begin
        macroblock_x_0 <= macroblock_x_0;
        macroblock_y_0 <= macroblock_y_0;
        error_0        <= error_0;
      end
 
  /*
   *
   * - Motion vector scaling: divide motion vectors by two for chrominance macroblocks. par. 7.6.3.7 Motion vectors for chrominance components.
   *   Division by two is evaluated as a/2 = ( a + signbit(a))>>> 1;
   *   part1: set up signbit registers.
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        mv_x_corr_0   <= 12'd0;
        mv_y_corr_0   <= 12'd0;
      end
    else if (clk_en)
      begin
        mv_x_corr_0   <= {11'b0, mv_x[12]};
        mv_y_corr_0   <= {11'b0, mv_y[12]};
      end
    else
      begin
        mv_x_corr_0   <= mv_x_corr_0;
        mv_y_corr_0   <= mv_y_corr_0;
     end
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_0          <= 3'b0;
        frame_picture_0  <= 1'b0;
        field_in_frame_0 <= 1'b0;
        field_0          <= 1'b0;
        component_0      <= 2'b0;
        mb_width_0       <= 8'd0;
        horizontal_size_0<= 14'd0;
        vertical_size_0  <= 14'd0;
        delta_x_0        <= 13'sd0;
        delta_y_0        <= 13'sd0;
        mv_x_0           <= 13'sd0;
        mv_y_0           <= 13'sd0;
        dta_0            <= {dta_width{1'b0}};
        valid_0          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_0          <= frame;
        frame_picture_0  <= frame_picture;
        field_in_frame_0 <= field_in_frame;
        field_0          <= field;
        component_0      <= component;
        mb_width_0       <= mb_width;
        horizontal_size_0<= horizontal_size;
        vertical_size_0  <= vertical_size;
        delta_x_0        <= delta_x;
        delta_y_0        <= delta_y;
        mv_x_0           <= mv_x;
        mv_y_0           <= mv_y;
        dta_0            <= dta_in;
        valid_0          <= valid_in;
      end
    else
      begin
        frame_0          <= frame_0;
        frame_picture_0  <= frame_picture_0;
        field_in_frame_0 <= field_in_frame_0;
        field_0          <= field_0;
        component_0      <= component_0;
        mb_width_0       <= mb_width_0;
        horizontal_size_0<= horizontal_size_0;
        vertical_size_0  <= vertical_size_0;
        delta_x_0        <= delta_x_0;
        delta_y_0        <= delta_y_0;
        mv_x_0           <= mv_x_0;
        mv_y_0           <= mv_y_0;
        dta_0            <= dta_0;
        valid_0          <= valid_0;
      end
 
  /*
   * Stage 1
   * - Motion vector scaling, part2: Apply motion vector correction and shift
   * - Calculate macroblock (x, y) coordinates in pixels
   */
 
  reg           [2:0]frame_1;
  reg                frame_picture_1;
  reg                field_in_frame_1;
  reg                field_1;
  reg           [1:0]component_1;
  reg           [7:0]mb_width_1;
  reg          [13:0]horizontal_size_1;
  reg          [13:0]vertical_size_1;
  reg signed   [12:0]delta_x_1;
  reg signed   [12:0]delta_y_1;
  reg signed   [12:0]mv_x_1;
  reg signed   [12:0]mv_y_1;
  reg signed   [12:0]pixel_x_1;
  reg signed   [12:0]pixel_y_1;
  reg [dta_width-1:0]dta_1;
  reg                valid_1;
  reg                error_1;
 
  always @(posedge clk)
    if (~rst)
      begin
        mv_x_1        <= 12'd0;
        mv_y_1        <= 12'd0;
      end
    else if ((clk_en) && (component_0 == COMP_Y)) /* luminance */
      begin
        mv_x_1        <= mv_x_0;
        mv_y_1        <= mv_y_0;
      end
    else if (clk_en) /* chrominance */
      begin
        mv_x_1        <= (mv_x_0 + mv_x_corr_0) >>> 1;
        mv_y_1        <= (mv_y_0 + mv_y_corr_0) >>> 1;
      end
    else
      begin
        mv_x_1        <= mv_x_1;
        mv_y_1        <= mv_y_1;
      end
 
  /*
   * Calculate macroblock (x, y) coordinates in pixels
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        pixel_x_1     <= 12'sd0;
        pixel_y_1     <= 12'sd0;
      end
    else if ((clk_en) && (component_0 == COMP_Y)) /* luminance: 16x16 pixels/macroblock */
      begin
        pixel_x_1     <= macroblock_x_0 <<< 4 ;
        pixel_y_1     <= macroblock_y_0 <<< 4;
      end
    else if (clk_en) /* 4:2:0 chrominance: 8x8 pixels/macroblock*/
      begin
        pixel_x_1     <= macroblock_x_0 <<< 3 ;
        pixel_y_1     <= macroblock_y_0 <<< 3;
      end
    else
      begin
        pixel_x_1     <= pixel_x_1;
        pixel_y_1     <= pixel_y_1;
      end
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_1          <= 3'b0;
        frame_picture_1  <= 1'b0;
        field_in_frame_1 <= 1'b0;
        field_1          <= 1'b0;
        component_1      <= 2'b0;
        mb_width_1       <= 8'd0;
        horizontal_size_1<= 14'd0;
        vertical_size_1  <= 14'd0;
        delta_x_1        <= 12'sd0;
        delta_y_1        <= 12'sd0;
        dta_1            <= {dta_width{1'b0}};
        valid_1          <= 1'b0;
        error_1          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_1          <= frame_0;
        frame_picture_1  <= frame_picture_0;
        field_in_frame_1 <= field_in_frame_0;
        field_1          <= field_0;
        component_1      <= component_0;
        mb_width_1       <= mb_width_0;
        horizontal_size_1<= horizontal_size_0;
        vertical_size_1  <= vertical_size_0;
        delta_x_1        <= delta_x_0;
        delta_y_1        <= delta_y_0;
        dta_1            <= dta_0;
        valid_1          <= valid_0;
        error_1          <= error_0;
      end
    else
      begin
        frame_1          <= frame_1;
        frame_picture_1  <= frame_picture_1;
        field_in_frame_1 <= field_in_frame_1;
        field_1          <= field_1;
        component_1      <= component_1;
        mb_width_1       <= mb_width_1;
        horizontal_size_1<= horizontal_size_1;
        vertical_size_1  <= vertical_size_1;
        delta_x_1        <= delta_x_1;
        delta_y_1        <= delta_y_1;
        dta_1            <= dta_1;
        valid_1          <= valid_1;
        error_1          <= error_1;
      end
 
  /*
   * Stage 2
   * - Motion vector scaling: split motion vector in pixel and halfpixel components.
   */
 
  reg           [2:0]frame_2;
  reg                frame_picture_2;
  reg                field_in_frame_2;
  reg                field_2;
  reg           [1:0]component_2;
  reg           [7:0]mb_width_2;
  reg          [13:0]horizontal_size_2;
  reg          [13:0]vertical_size_2;
  reg signed   [12:0]delta_x_2;
  reg signed   [12:0]delta_y_2;
  reg signed   [12:0]mv_x_2;
  reg signed   [12:0]mv_y_2;
  reg signed   [12:0]pixel_x_2;
  reg signed   [12:0]pixel_y_2;
  reg                halfpixel_x_2;
  reg                halfpixel_y_2;
  reg [dta_width-1:0]dta_2;
  reg                valid_2;
  reg                error_2;
 
  always @(posedge clk)
    if (~rst)
      begin
        mv_x_2        <= 12'sd0;
        halfpixel_x_2 <= 1'd0;
        mv_y_2        <= 12'sd0;
        halfpixel_y_2 <= 1'd0;
      end
    else if (clk_en)
      begin
        mv_x_2        <= {mv_x_1[12], mv_x_1[12:1]};
        halfpixel_x_2 <= mv_x_1[0];
        mv_y_2        <= {mv_y_1[12], mv_y_1[12:1]};
        halfpixel_y_2 <= mv_y_1[0];
      end
    else
      begin
        mv_x_2        <= mv_x_2;
        halfpixel_x_2 <= halfpixel_x_2;
        mv_y_2        <= mv_y_2;
        halfpixel_y_2 <= halfpixel_y_2;
      end
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_2          <= 3'b0;
        frame_picture_2  <= 1'b0;
        field_in_frame_2 <= 1'b0;
        field_2          <= 1'b0;
        component_2      <= 2'b0;
        mb_width_2       <= 8'd0;
        horizontal_size_2<= 14'd0;
        vertical_size_2  <= 14'd0;
        delta_x_2        <= 12'sd0;
        delta_y_2        <= 12'sd0;
        pixel_x_2        <= 12'sd0;
        pixel_y_2        <= 12'sd0;
        dta_2            <= {dta_width{1'b0}};
        valid_2          <= 1'b0;
        error_2          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_2          <= frame_1;
        frame_picture_2  <= frame_picture_1;
        field_in_frame_2 <= field_in_frame_1;
        field_2          <= field_1;
        component_2      <= component_1;
        mb_width_2       <= mb_width_1;
        horizontal_size_2<= horizontal_size_1;
        vertical_size_2  <= vertical_size_1;
	delta_x_2        <= delta_x_1;
	delta_y_2        <= delta_y_1;
        pixel_x_2        <= pixel_x_1;
        pixel_y_2        <= pixel_y_1;
        dta_2            <= dta_1;
        valid_2          <= valid_1;
        error_2          <= error_1;
      end
    else
      begin
        frame_2          <= frame_2;
        frame_picture_2  <= frame_picture_2;
        field_in_frame_2 <= field_in_frame_2;
        field_2          <= field_2;
        component_2      <= component_2;
        mb_width_2       <= mb_width_2;
        horizontal_size_2<= horizontal_size_2;
        vertical_size_2  <= vertical_size_2;
	delta_x_2        <= delta_x_2;
	delta_y_2        <= delta_y_2;
        pixel_x_2        <= pixel_x_2;
        pixel_y_2        <= pixel_y_2;
        dta_2            <= dta_2;
        valid_2          <= valid_2;
        error_2          <= error_2;
      end
 
  /*
   * Stage 3
   * Frame and field images
   * - If top field of a field image
   *     - multiply y by two
   *     - multiply motion vector y by two
   *     - multiply delta y by two
   * - If bottom field of a field image
   *     - multiply y by two and add one
   *     - multiply motion vector y by two
   *     - multiply delta y by two
   * - If frame image and field_in_frame is not set
   *     - pass on y, motion vector y and delta y unchanged
   * - If frame image and field_in_frame is set and field is top field
   *     - pass on y unchanged
   *     - multiply motion vector y by two
   *     - multiply delta y by two
   * - If frame image and field_in_frame is set and field is bottom field
   *     - add one to y
   *     - multiply motion vector y by two
   *     - multiply delta y by two
   */
 
  reg           [2:0]frame_3;
  reg           [1:0]component_3;
  reg           [7:0]mb_width_3;
  reg          [13:0]horizontal_size_3;
  reg          [13:0]vertical_size_3;
  reg signed   [12:0]delta_x_3;
  reg signed   [12:0]delta_y_3;
  reg signed   [12:0]mv_x_3;
  reg signed   [12:0]mv_y_3;
  reg signed   [12:0]pixel_x_3;
  reg signed   [12:0]pixel_y_3;
  reg                halfpixel_x_3;
  reg                halfpixel_y_3;
  reg [dta_width-1:0]dta_3;
  reg                valid_3;
  reg                error_3;
 
  always @(posedge clk)
    if (~rst)
      begin
        delta_y_3 <= 13'sd0;
	mv_y_3    <= 13'sd0;
	pixel_y_3 <= 13'sd0;
      end
    else if (clk_en && ~frame_picture_2) /* field picture */
      begin
        delta_y_3 <= delta_y_2 <<< 1;
	mv_y_3    <= mv_y_2 <<< 1;
	pixel_y_3 <= {pixel_y_2[11:0], field_2}; /* multiply by 2; add 1 if bottom field */
      end
    else if (clk_en && frame_picture_2 && field_in_frame_2 && field_2) /* field-in-frame, bottom field */
      begin
        delta_y_3 <= delta_y_2 <<< 1;
	mv_y_3    <= mv_y_2 <<< 1;
	pixel_y_3 <= pixel_y_2 + 12'sd1;
      end
    else if (clk_en && frame_picture_2 && field_in_frame_2 && ~field_2) /* field-in-frame, top field */
      begin
        delta_y_3 <= delta_y_2 <<< 1;
	mv_y_3    <= mv_y_2 <<< 1;
	pixel_y_3 <= pixel_y_2;
      end
    else if (clk_en && frame_picture_2 && ~field_in_frame_2) /* frame picture */
      begin
        delta_y_3 <= delta_y_2;
	mv_y_3    <= mv_y_2;
	pixel_y_3 <= pixel_y_2;
      end
    else
      begin
        delta_y_3 <= delta_y_3;
	mv_y_3    <= mv_y_3;
	pixel_y_3 <= pixel_y_3;
      end
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_3          <= 3'b0;
        component_3      <= 2'b0;
        mb_width_3       <= 8'd0;
        horizontal_size_3<= 14'd0;
        vertical_size_3  <= 14'd0;
        delta_x_3        <= 12'sd0;
        mv_x_3           <= 12'sd0;
	pixel_x_3        <= 13'sd0;
	halfpixel_x_3    <= 1'b0;
	halfpixel_y_3    <= 1'b0;
        dta_3            <= {dta_width{1'b0}};
        valid_3          <= 1'b0;
        error_3          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_3          <= frame_2;
        component_3      <= component_2;
        mb_width_3       <= mb_width_2;
        horizontal_size_3<= horizontal_size_2;
        vertical_size_3  <= vertical_size_2;
        delta_x_3        <= delta_x_2;
        mv_x_3           <= mv_x_2;
	pixel_x_3        <= pixel_x_2;
	halfpixel_x_3    <= halfpixel_x_2;
	halfpixel_y_3    <= halfpixel_y_2;
        dta_3            <= dta_2;
        valid_3          <= valid_2;
        error_3          <= error_2;
      end
    else
      begin
        frame_3          <= frame_3;
        component_3      <= component_3;
        mb_width_3       <= mb_width_3;
        horizontal_size_3<= horizontal_size_3;
        vertical_size_3  <= vertical_size_3;
        delta_x_3        <= delta_x_3;
        mv_x_3           <= mv_x_3;
	pixel_x_3        <= pixel_x_3;
	halfpixel_x_3    <= halfpixel_x_3;
	halfpixel_y_3    <= halfpixel_y_3;
        dta_3            <= dta_3;
        valid_3          <= valid_3;
        error_3          <= error_3;
      end
 
  /*
   * Stage 4
   * Add (delta_x, delta_y) to (pixel_x, pixel_y)
   */
 
  reg           [2:0]frame_4;
  reg           [1:0]component_4;
  reg           [7:0]mb_width_4;
  reg signed   [12:0]mv_x_4;
  reg signed   [12:0]mv_y_4;
  reg signed   [12:0]pixel_x_4;
  reg signed   [12:0]pixel_y_4;
  reg                halfpixel_x_4;
  reg                halfpixel_y_4;
  reg signed   [12:0]width_4; // width in pixels of component
  reg signed   [12:0]height_4; // width in pixels of component
  reg [dta_width-1:0]dta_4;
  reg                valid_4;
  reg                error_4;
 
  always @(posedge clk)
    if (~rst)
      begin
        pixel_x_4     <= 12'sd0;
        pixel_y_4     <= 12'sd0;
      end
    else if (clk_en)
      begin
        pixel_x_4     <= pixel_x_3 + delta_x_3;
        pixel_y_4     <= pixel_y_3 + delta_y_3;
      end
    else
      begin
        pixel_x_4     <= pixel_x_4;
        pixel_y_4     <= pixel_y_4;
      end
 
  always @(posedge clk)
    if (~rst)
      begin
        width_4       <= 14'd0;
        height_4      <= 14'd0;
      end
    else if (clk_en && (component_3 == COMP_Y))
      begin
        width_4       <= {1'b0, horizontal_size_3[11:0]};
        height_4      <= {1'b0, vertical_size_3[11:0]};
      end
    else if (clk_en)
      begin
        width_4       <= {2'b0, horizontal_size_3[11:1]};
        height_4      <= {2'b0, vertical_size_3[11:1]};
      end
    else
      begin
        width_4       <= width_4;
        height_4      <= height_4;
      end
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_4          <= 3'b0;
        component_4      <= 2'b0;
        mb_width_4       <= 8'd0;
        mv_x_4           <= 12'sd0;
        mv_y_4           <= 12'sd0;
	halfpixel_x_4    <= 1'b0;
	halfpixel_y_4    <= 1'b0;
        dta_4            <= {dta_width{1'b0}};
        valid_4          <= 1'b0;
        error_4          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_4          <= frame_3;
        component_4      <= component_3;
        mb_width_4       <= mb_width_3;
	mv_x_4           <= mv_x_3;
	mv_y_4           <= mv_y_3;
	halfpixel_x_4    <= halfpixel_x_3;
	halfpixel_y_4    <= halfpixel_y_3;
        dta_4            <= dta_3;
        valid_4          <= valid_3;
        error_4          <= error_3;
      end
    else
      begin
        frame_4          <= frame_4;
        component_4      <= component_4;
        mb_width_4       <= mb_width_4;
	mv_x_4           <= mv_x_4;
	mv_y_4           <= mv_y_4;
	halfpixel_x_4    <= halfpixel_x_4;
	halfpixel_y_4    <= halfpixel_y_4;
        dta_4            <= dta_4;
        valid_4          <= valid_4;
        error_4          <= error_4;
      end
 
  /*
   * Stage 5
   * Add (mv_x, mv_y) to (pixel_x, pixel_y)
   */
 
  reg           [2:0]frame_5;
  reg           [1:0]component_5;
  reg           [7:0]mb_width_5;
  reg signed   [12:0]pixel_x_5;
  reg signed   [12:0]pixel_y_5;
  reg                halfpixel_x_5;
  reg                halfpixel_y_5;
  reg signed   [12:0]width_5;
  reg signed   [12:0]height_5;
  reg [dta_width-1:0]dta_5;
  reg                valid_5;
  reg                error_5;
 
  always @(posedge clk)
    if (~rst)
      begin
        pixel_x_5     <= 12'd0;
        pixel_y_5     <= 12'd0;
      end
    else if (clk_en)
      begin
        pixel_x_5     <= pixel_x_4 + mv_x_4;
        pixel_y_5     <= pixel_y_4 + mv_y_4;
      end
    else
      begin
        pixel_x_5     <= pixel_x_5;
        pixel_y_5     <= pixel_y_5;
      end
 
  always @(posedge clk)
    if (~rst)
      begin
        width_5       <= 13'sd0;
        height_5      <= 13'sd0;
      end
    else if (clk_en && ((width_4 == 13'sd0) || (height_4 == 13'sd0)))
      begin
        width_5       <= 13'sd0;
        height_5      <= 13'sd0;
      end
    else if (clk_en)
      begin
        width_5       <= width_4 - 13'sd1;
        height_5      <= height_4 - 13'sd1;
      end
    else
      begin
        width_5       <= width_5;
        height_5      <= height_5;
      end
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_5          <= 3'b0;
        component_5      <= 2'b0;
        mb_width_5       <= 8'd0;
	halfpixel_x_5    <= 1'b0;
	halfpixel_y_5    <= 1'b0;
        dta_5            <= {dta_width{1'b0}};
        valid_5          <= 1'b0;
        error_5          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_5          <= frame_4;
        component_5      <= component_4;
        mb_width_5       <= mb_width_4;
	halfpixel_x_5    <= halfpixel_x_4;
	halfpixel_y_5    <= halfpixel_y_4;
        dta_5            <= dta_4;
        valid_5          <= valid_4;
        error_5          <= error_4;
      end
    else
      begin
        frame_5          <= frame_5;
        component_5      <= component_5;
        mb_width_5       <= mb_width_5;
	halfpixel_x_5    <= halfpixel_x_5;
	halfpixel_y_5    <= halfpixel_y_5;
        dta_5            <= dta_5;
        valid_5          <= valid_5;
        error_5          <= error_5;
      end
 
  /*
   * Stage 6
   * - clip to image borders
   * - convert pixel_x, pixel_y to unsigned.
   * At this point pixel_x, pixel_y, halfpixel_x and halfpixel_y have been fully computed.
   */
 
  reg           [2:0]frame_6;
  reg           [1:0]component_6;
  reg           [7:0]mb_width_6;
  reg          [11:0]pixel_x_6;
  reg          [11:0]pixel_y_6;
  reg           [2:0]offset_x_6;
  reg                halfpixel_x_6;
  reg                halfpixel_y_6;
  reg [dta_width-1:0]dta_6;
  reg                valid_6;
  reg                error_6;
 
  wire signed  [12:0]horizontal_diff = pixel_x_5 - width_5;
  wire signed  [12:0]vertical_diff   = pixel_y_5 - height_5;
 
  /*
   * Even though par. 7.6.3.8 guarantees:
   * "it is a restriction on the bitstream that reconstructed motion vectors shall not
   * refer to samples outside the boundary of the coded picture."
   * we clip coordinates to safe ranges.
   * For luminance:
   * Clip pixel_x to range [0, horizontal_size-1]
   * Clip pixel_y to range [0, vertical_size-1]
   * For chrominance:
   * Clip pixel_x to range [0, (horizontal_size>>1)-1]
   * Clip pixel_y to range [0, (vertical_size>>1)-1]
   * Convert pixel_x, pixel_y to unsigned
   */
 
  always @(posedge clk)
    if (~rst) pixel_x_6 <= 12'd0;
    else if (clk_en && pixel_x_5[12]) pixel_x_6 <= 12'd0; // if pixel_x_5 < 0, clip to 0
    else if (clk_en && horizontal_diff[12]) pixel_x_6 <= pixel_x_5[11:0]; // if pixel_x_5 > horizontal_size - 1, clip to horizontal_size - 1
    else if (clk_en) pixel_x_6 <= width_5[11:0];
    else pixel_x_6 <= pixel_x_6;
 
  always @(posedge clk)
    if (~rst) pixel_y_6 <= 12'd0;
    else if (clk_en && pixel_y_5[12]) pixel_y_6 <= 12'd0; // if pixel_y_5 < 0, clip to 0
    else if (clk_en && vertical_diff[12]) pixel_y_6 <= pixel_y_5[11:0]; // if pixel_y_5 > vertical_size - 1, clip to vertical_size - 1
    else if (clk_en) pixel_y_6 <= height_5[11:0];
    else pixel_y_6 <= pixel_y_6;
 
  /*
   *   Calculate byte offset within 8-byte word (offset_x)
   */
 
  always @(posedge clk)
    if (~rst) offset_x_6 <= 3'd0;
    else if (clk_en) offset_x_6 <= pixel_x_5[2:0];
    else offset_x_6 <= offset_x_6;
 
  always @(posedge clk)
    if (~rst) error_6 <= 1'b0;
    else if (clk_en) error_6 <= error_5;
    else error_6 <= error_6;
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_6          <= 3'b0;
        component_6      <= 2'b0;
        mb_width_6       <= 8'd0;
	halfpixel_x_6    <= 1'b0;
	halfpixel_y_6    <= 1'b0;
        dta_6            <= {dta_width{1'b0}};
        valid_6          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_6          <= frame_5;
        component_6      <= component_5;
        mb_width_6       <= mb_width_5;
	halfpixel_x_6    <= halfpixel_x_5;
	halfpixel_y_6    <= halfpixel_y_5;
        dta_6            <= dta_5;
        valid_6          <= valid_5;
      end
    else
      begin
        frame_6          <= frame_6;
        component_6      <= component_6;
        mb_width_6       <= mb_width_6;
	halfpixel_x_6    <= halfpixel_x_6;
	halfpixel_y_6    <= halfpixel_y_6;
        dta_6            <= dta_6;
        valid_6          <= valid_6;
      end
 
  /*
   * Stage 7
   * Line stride, part1.
   * - multiply y with mb_width
   * - split x into two parts: 
   *   - byte offset within 8-byte word (offset_x)
   *   - number of 8-byte words (word_x)
   */
 
  reg           [2:0]frame_7;
  reg           [1:0]component_7;
  reg                halfpixel_x_7;
  reg                halfpixel_y_7;
  reg          [21:0]address_7;
  reg           [2:0]offset_x_7;
  reg           [8:0]word_x_7;
  reg [dta_width-1:0]dta_7;
  reg                valid_7;
  reg                error_7;
 
  always @(posedge clk)
    if (~rst) address_7 <= 22'd0;
    else if (clk_en) address_7 <= pixel_y_6 * mb_width_6; /* Instantiate a multiplier :( */
    else address_7 <= address_7;
 
  always @(posedge clk)
    if (~rst) word_x_7 <= 3'd0;
    else if (clk_en) word_x_7 <= pixel_x_6[11:3];
    else word_x_7 <= word_x_7;
 
  /* if mb_width is zero we don't know MPEG2 horizontal picture size */
  always @(posedge clk)
    if (~rst) error_7 <= 1'b0;
    else if (clk_en) error_7 <= error_6 || (mb_width_6 == 8'd0); 
    else error_7 <= error_7;
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_7          <= 3'b0;
        component_7      <= 2'b0;
	halfpixel_x_7    <= 1'b0;
	halfpixel_y_7    <= 1'b0;
        offset_x_7       <= 3'd0;
        dta_7            <= {dta_width{1'b0}};
        valid_7          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_7          <= frame_6;
        component_7      <= component_6;
	halfpixel_x_7    <= halfpixel_x_6;
	halfpixel_y_7    <= halfpixel_y_6;
        offset_x_7       <= offset_x_6;
        dta_7            <= dta_6;
        valid_7          <= valid_6;
      end
    else
      begin
        frame_7          <= frame_7;
        component_7      <= component_7;
	halfpixel_x_7    <= halfpixel_x_7;
	halfpixel_y_7    <= halfpixel_y_7;
        offset_x_7       <= offset_x_7;
        dta_7            <= dta_7;
        valid_7          <= valid_7;
      end
 
  /*
   * Stage 8
   * Line stride, part 2.
   * - if macroblock is a luminance block, multiply address by two
   *   (luminance blocks are 16 pixels (bytes) wide; chrominance blocks only 8)
   * - extend word_x
   */
 
  reg           [2:0]frame_8;
  reg           [1:0]component_8;
  reg                halfpixel_x_8;
  reg                halfpixel_y_8;
  reg          [21:0]address_8;
  reg           [2:0]offset_x_8;
  reg          [21:0]word_x_8;
  reg [dta_width-1:0]dta_8;
  reg                valid_8;
  reg                error_8;
 
  always @(posedge clk)
    if (~rst) address_8 <= 22'd0;
    else if (clk_en && (component_7 == COMP_Y)) address_8 <= address_7 << 1;
    else if (clk_en) address_8 <= address_7;
    else address_8 <= address_8;
 
  always @(posedge clk)
    if (~rst) word_x_8 <= 22'd0;
    else if (clk_en) word_x_8 <= word_x_7;
    else word_x_8 <= word_x_8;
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        frame_8          <= 3'b0;
        component_8      <= 2'b0;
	halfpixel_x_8    <= 1'b0;
	halfpixel_y_8    <= 1'b0;
	offset_x_8       <= 3'd0;
        dta_8            <= {dta_width{1'b0}};
        valid_8          <= 1'b0;
        error_8          <= 1'b0;
      end
    else if (clk_en)
      begin
        frame_8          <= frame_7;
        component_8      <= component_7;
	halfpixel_x_8    <= halfpixel_x_7;
	halfpixel_y_8    <= halfpixel_y_7;
	offset_x_8       <= offset_x_7;
        dta_8            <= dta_7;
        valid_8          <= valid_7;
        error_8          <= error_7;
      end
    else
      begin
        frame_8          <= frame_8;
        component_8      <= component_8;
	halfpixel_x_8    <= halfpixel_x_8;
	halfpixel_y_8    <= halfpixel_y_8;
	offset_x_8       <= offset_x_8;
        dta_8            <= dta_8;
        valid_8          <= valid_8;
        error_8          <= error_8;
      end
 
  /*
   * Stage 9
   * Line stride, part 3.
   * - add word_x to address
   * - determine begin/end addresses of frame in memory.
   */
 
  reg          [21:0]address_9;
  reg          [21:0]base_address_9;
  reg          [21:0]end_address_9;
  reg                halfpixel_x_9;
  reg                halfpixel_y_9;
  reg           [2:0]offset_x_9;
  reg [dta_width-1:0]dta_9;
  reg                valid_9;
  reg                error_9;
 
  always @(posedge clk)
    if (~rst) address_9 <= 22'd0;
    else if (clk_en) address_9 <= address_8 + word_x_8;
    else address_9 <= address_9;
 
  always @(posedge clk)
    if(~rst) base_address_9 <= 22'b0;
    else if (clk_en) 
      case ({frame_8, component_8}) 
        {3'd0, COMP_Y  }: base_address_9 <= FRAME_0_Y; 
        {3'd0, COMP_CR }: base_address_9 <= FRAME_0_CR; 
        {3'd0, COMP_CB }: base_address_9 <= FRAME_0_CB; 
        {3'd1, COMP_Y  }: base_address_9 <= FRAME_1_Y; 
        {3'd1, COMP_CR }: base_address_9 <= FRAME_1_CR; 
        {3'd1, COMP_CB }: base_address_9 <= FRAME_1_CB; 
        {3'd2, COMP_Y  }: base_address_9 <= FRAME_2_Y; 
        {3'd2, COMP_CR }: base_address_9 <= FRAME_2_CR; 
        {3'd2, COMP_CB }: base_address_9 <= FRAME_2_CB; 
        {3'd3, COMP_Y  }: base_address_9 <= FRAME_3_Y; 
        {3'd3, COMP_CR }: base_address_9 <= FRAME_3_CR; 
        {3'd3, COMP_CB }: base_address_9 <= FRAME_3_CB; 
        {3'd4, COMP_Y  }: base_address_9 <= OSD; 
        default           base_address_9 <= ADDR_ERR;
      endcase
    else base_address_9 <= base_address_9;
 
  always @(posedge clk)
    if(~rst) end_address_9 <= 22'b0;
    else if (clk_en) 
      case (component_8) 
        COMP_Y  : end_address_9 <= (22'd1 << WIDTH_Y); 
        COMP_CR,
        COMP_CB : end_address_9 <= (22'd1 << WIDTH_C); 
        default   end_address_9 <= 22'b0;
      endcase
    else end_address_9 <= end_address_9;
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
	halfpixel_x_9    <= 1'b0;
	halfpixel_y_9    <= 1'b0;
	offset_x_9       <= 3'd0;
        dta_9            <= {dta_width{1'b0}};
        valid_9          <= 1'b0;
        error_9          <= 1'b0;
      end
    else if (clk_en)
      begin
	halfpixel_x_9    <= halfpixel_x_8;
	halfpixel_y_9    <= halfpixel_y_8;
	offset_x_9       <= offset_x_8;
        dta_9            <= dta_8;
        valid_9          <= valid_8;
        error_9          <= error_8;
      end
    else
      begin
	halfpixel_x_9    <= halfpixel_x_9;
	halfpixel_y_9    <= halfpixel_y_9;
	offset_x_9       <= offset_x_9;
        dta_9            <= dta_9;
        valid_9          <= valid_9;
        error_9          <= error_9;
      end
 
  /*
   * Stage 10
   * - add base_address to address
   * - if address exceeds end_address, set error flag.
   */
 
  reg          [21:0]address_10;
  reg                halfpixel_x_10;
  reg                halfpixel_y_10;
  reg           [2:0]offset_x_10;
  reg [dta_width-1:0]dta_10;
  reg                valid_10;
  reg                error_10;
 
  /*
   * add base_address to address
   */
 
  always @(posedge clk)
    if (~rst) address_10 <= 22'd0;
    else if (clk_en) address_10 <= address_9 + base_address_9;
    else address_10 <= address_10;
 
  /*
   * if address exceeds end_address, set error flag.
   */
 
  always @(posedge clk)
    if (~rst) error_10 <= 1'b0;
    else if (clk_en) error_10 <= error_9 || (address_9 > end_address_9);
    else error_10 <= error_10;
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
	halfpixel_x_10    <= 1'b0;
	halfpixel_y_10    <= 1'b0;
	offset_x_10       <= 3'd0;
        dta_10            <= {dta_width{1'b0}};
        valid_10          <= 1'b0;
      end
    else if (clk_en)
      begin
	halfpixel_x_10    <= halfpixel_x_9;
	halfpixel_y_10    <= halfpixel_y_9;
	offset_x_10       <= offset_x_9;
        dta_10            <= dta_9;
        valid_10          <= valid_9;
      end
    else
      begin
	halfpixel_x_10    <= halfpixel_x_10;
	halfpixel_y_10    <= halfpixel_y_10;
	offset_x_10       <= offset_x_10;
        dta_10            <= dta_10;
        valid_10          <= valid_10;
      end
 
  /*
   * Stage 11
   * - Does nothing. (passes on data)
   */
 
  reg          [21:0]address_11;
  reg                halfpixel_x_11;
  reg                halfpixel_y_11;
  reg           [2:0]offset_x_11;
  reg [dta_width-1:0]dta_11;
  reg                valid_11;
  reg                error_11;
 
  always @(posedge clk)
    if (~rst) error_11 <= 1'b0;
    else if (clk_en) error_11 <= error_10;
    else error_11 <= error_11;
 
  /*
   * Pass on other registers
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        address_11        <= 22'b0;
	halfpixel_x_11    <= 1'b0;
	halfpixel_y_11    <= 1'b0;
	offset_x_11       <= 3'd0;
        dta_11            <= {dta_width{1'b0}};
        valid_11          <= 1'b0;
      end
    else if (clk_en)
      begin
        address_11        <= address_10;
	halfpixel_x_11    <= halfpixel_x_10;
	halfpixel_y_11    <= halfpixel_y_10;
	offset_x_11       <= offset_x_10;
        dta_11            <= dta_10;
        valid_11          <= valid_10;
      end
    else
      begin
        address_11        <= address_11;
	halfpixel_x_11    <= halfpixel_x_11;
	halfpixel_y_11    <= halfpixel_y_11;
	offset_x_11       <= offset_x_11;
        dta_11            <= dta_11;
        valid_11          <= valid_11;
      end
 
  /*
   * Stage 12
   * - assign output variables
   * - if error flag set, set address to ADDR_ERR
   */
 
  always @(posedge clk)
    if (~rst) address <= 22'd0;
    else if (clk_en && error_11) address <= ADDR_ERR;
    else if (clk_en) address <= address_11;
    else address <= address;
 
  /*
   * Assign outputs
   */
 
  always @(posedge clk)
    if (~rst)
      begin
	halfpixel_x       <= 1'b0;
	halfpixel_y       <= 1'b0;
	offset_x          <= 3'd0;
        dta_out           <= {dta_width{1'b0}};
        valid_out         <= 1'b0;
      end
    else if (clk_en)
      begin
	halfpixel_x       <= halfpixel_x_11;
	halfpixel_y       <= halfpixel_y_11;
	offset_x          <= offset_x_11;
        dta_out           <= dta_11;
        valid_out         <= valid_11;
      end
    else
      begin
	halfpixel_x       <= halfpixel_x;
	halfpixel_y       <= halfpixel_y;
	offset_x          <= offset_x;
        dta_out           <= dta_out;
        valid_out         <= valid_out;
      end
 
 
`ifdef DEBUG
  always @(posedge clk)
    begin
      $strobe("%m\tclk_en: %d frame: %d frame_picture: %d field_in_frame: %d field: %d component: %d mb_width: %d macroblock_address: %h delta_x: %d delta_y: %d mv_x: %d mv_y: %d dta_in: %d valid_in: %d", 
                   clk_en, frame, frame_picture, field_in_frame, field, component, mb_width, macroblock_address, delta_x, delta_y, mv_x, mv_y, dta_in, valid_in);
      $strobe("%m\tclk_en: %d address: %h offset_x: %d halfpixel_x: %d halfpixel_y: %d dta_out: %d valid_out: %d", 
                   clk_en, address, offset_x, halfpixel_x, halfpixel_y, dta_out, valid_out);
      $strobe("%m\tclk_en: %d frame_6: %d component_6: %d pixel_x_6: %d pixel_y_6: %d offset_x_6: %d halfpixel_x_6: %d halfpixel_y_6: %d dta_6: %d valid_6: %d", 
                   clk_en, frame_6, component_6, pixel_x_6, pixel_y_6, offset_x_6, halfpixel_x_6, halfpixel_y_6, dta_6, valid_6);
 
    end
`endif
 
endmodule
/* not truncated */
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2019 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.