⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yscale.v

📁 一个视频信号输入的verilog源代码
💻 V
字号:
// ================================================================================
// (c) 2004 Altera Corporation. All rights reserved.
// Altera products are protected under numerous U.S. and foreign patents, maskwork
// rights, copyrights and other intellectual property laws.
// 
// This reference design file, and your use thereof, is subject to and governed
// by the terms and conditions of the applicable Altera Reference Design License
// Agreement (either as signed by you, agreed by you upon download or as a
// "click-through" agreement upon installation andor found at www.altera.com).
// By using this reference design file, you indicate your acceptance of such terms
// and conditions between you and Altera Corporation.  In the event that you do
// not agree with such terms and conditions, you may not use the reference design
// file and please promptly destroy any copies you have made.
// 
// This reference design file is being provided on an "as-is" basis and as an
// accommodation and therefore all warranties, representations or guarantees of
// any kind (whether express, implied or statutory) including, without limitation,
// warranties of merchantability, non-infringement, or fitness for a particular
// purpose, are specifically disclaimed.  By making this reference design file
// available, Altera expressly does not recommend, suggest or require that this
// reference design file be used in combination with any other product not
// provided by Altera.
// ================================================================================
//---------------------------------------------------------------------------
// Y scaling
//---------------------------------------------------------------------------
`timescale 1ns/1ns

module yscale (
	       clk,
	       reset_n,

	       // input
	       rgb_empty,
	       rgb_rd,
	       rgb_in,

	       // output
	       rgb_out,
	       rgb_out_en,
	       eof,

	       // control registers
	       yscale_reg,
	       xlen,
	       ylen
	       );

  input clk;
  input reset_n;

  input rgb_empty;
  output rgb_rd;
  input [17:0] rgb_in;

  output [17:0] rgb_out;
  output 	rgb_out_en;
  output 	eof;

  input [15:0] 	yscale_reg;
  input [9:0] 	xlen;
  input [8:0] 	ylen;

  reg [9:0] 	line_addr;
  reg [17:0] 	line1_rdata;
  wire [17:0] 	line1_0_rdata;
  wire [17:0] 	line1_1_rdata;
  wire [17:0] 	line1_2_rdata;
  reg [17:0] 	line2_rdata;
  wire [17:0] 	line2_0_rdata;
  wire [17:0] 	line2_1_rdata;
  wire [17:0] 	line2_2_rdata;

  reg [20:0] output_line;
  wire [20:0] 	next_line;
  wire [20:0] 	next_line2;
  wire [3:0] 	line_diff;
  wire [3:0] 	line_diff2;
  wire 		line_wren;
  wire 		line_end;

  wire [3:0] 	scale_int = yscale_reg[15:12];
  wire [5:0] 	scale_frac = yscale_reg[11:6];
  
  //---------------------------------------------------------------------------
  // Clock enable
  //
  // To allow for a max 3x scaling in the X scaling module, this module must
  // only output pixels on every third clock.
  //---------------------------------------------------------------------------
  reg 	[1:0]	clk_div;
  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      clk_div <= 2'b0;
    else if (clk_div == 2'b10)
      clk_div <= 2'b00;
    else
      clk_div <= clk_div + 2'b01;

  wire 		clk_en = (clk_div == 2'b10);
      
  //---------------------------------------------------------------------------
  // Input state machine
  //
  // Idle during vertical blanking, we need to read two complete lines before
  // we begin generating output lines.
  //---------------------------------------------------------------------------
  reg [3:0] 	in_state;
  parameter in_idle	= 4'b0000,
	    in_line2	= 4'b0001,
	    in_do	= 4'b0010,
	    in_new	= 4'b0011,
	    in_skip1	= 4'b0100,
	    in_skip2	= 4'b0101,
	    in_flush	= 4'b0110,
	    in_wait1	= 4'b0111,
	    in_wait2	= 4'b1000;

  reg 		in_done;
  reg 		eof;
  reg [8:0] 	line_in;
  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      line_in <= 9'b0;
    else if ((in_state == in_flush) & line_end
		& (next_line > {line_in, 12'b0})
	     | in_done & (in_state == in_skip1) & line_end & line_wren
		& (output_line > {line_in, 12'b0})
	     | in_done & (in_state == in_new) & line_end & line_wren
		& (next_line > {line_in, 12'b0}))
      line_in <= 9'b0;
    else if (line_end & line_wren)
      line_in <= line_in + 9'b1;

  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      eof <= 1'b0;
    else eof <= (clk_en & (in_state == in_flush) & line_end
			& (next_line > {line_in, 12'b0})
		 | in_done & (in_state == in_skip1) & line_end & line_wren
			& (output_line > {line_in, 12'b0})
		 | in_done & (in_state == in_new) & line_end & line_wren
			& (next_line > {line_in, 12'b0}));
      
  // No more input lines coming
  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      in_done <= 1'b0;
    else if (line_end & line_wren & (line_in == ylen) & (yscale_reg[15:12] != 4'b0))
      in_done <= 1'b1;
    else if (output_line > {line_in, 12'b0})
      in_done <= 1'b0;

  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      in_state <= in_idle;
    else if (line_end & line_wren & (line_in == ylen))
      in_state <= in_wait2;
    else if (clk_en)
      case (in_state)
	in_idle:
	  // Idle or reading in first line of frame
	  if (line_end & line_wren)
	    in_state <= in_line2;
	  else
	    in_state <= in_idle;
	
	in_line2:
	  // Reading in second line of frame
	  if (line_end & line_wren & (yscale_reg[15:12] == 4'h0))
	    // Scale up
	    in_state <= in_do;
	  else if (line_end & line_wren)
	    // Scale down or x1
	    in_state <= in_new;
	  else
	    in_state <= in_line2;
	
	in_do:
	  // Processing stored line
	  if (line_end & (line_diff2 != 4'h0))
	    // Get next line
	    in_state <= in_new;
	  else if (line_end)
	    // Gap to allow X scale time to process end of line
	    in_state <= in_wait1;
	  else
	    in_state <= in_do;
	
	in_new:
	  // Reading in new line and processing previous lines
	  if (line_end & line_wren & (yscale_reg[15:12] == 4'h0) & (line_diff2 < 4'h2))
	    // Scale up
	    in_state <= in_wait1;
	  else if (line_end & line_wren & (yscale_reg[15:12] != 4'h0) & (line_diff == 4'h2))
	    // Scale down or x1
	    in_state <= in_skip1;
	  else if (line_end & line_wren & (yscale_reg[15:12] != 4'h0) & (line_diff > 4'h2))
	    // Scale down or x1
	    in_state <= in_skip2;
	  else if (in_done & (next_line > {line_in, 12'b0}))
	    // Scale down or x1 no more input lines
	    in_state <= in_idle;
	  else
	    in_state <= in_new;
	
	in_skip2:
	  // Reading in new line with no processing
	  if (line_end & line_wren | in_done)
	    in_state <= in_skip1;
	  else
	    in_state <= in_skip2;
	
	in_skip1:
	  // Reading in new line with no processing
	  if (line_end & line_wren)
	    in_state <= in_new;
	  else if (in_done & (output_line > {line_in, 12'b0}))
	    in_state <= in_idle;
	  else
	    in_state <= in_skip1;

	in_flush:
	  // Flushing stored pixels
	  if (line_end & (next_line > {line_in, 12'b0}))
	    in_state <= in_idle;
	  else if (line_end)
	    in_state <= in_wait2;
	  else
	    in_state <= in_flush;

	in_wait1:
	  // Delay to allow X scale time to process end of line
	  in_state <= in_do;
	
	in_wait2:
	  // Delay to allow X scale time to process end of line
	  in_state <= in_flush;
	
	default:
	  in_state <= in_idle;
      endcase

  //---------------------------------------------------------------------------
  // Output line position
  //
  // Scale factor is added to a running total to tell us where an output line
  // is to be generated.
  //
  // E.g. yscale reg is 15'h1800 (meaning 'd1.5) or a scale factor of 2/3
  // Output lines are 1, 2.5, 4, ... The fractional part tell us the proprtions
  // of the two lines to be added (1-fraction)*line 1 + fraction*line2.
  //
  // The difference in the integer parts of the current and next two output
  // lines tell us when to load the next input line.
  //---------------------------------------------------------------------------
  assign next_line = output_line + yscale_reg;
  assign next_line2 = next_line + yscale_reg;
  
  assign line_diff = next_line[15:12] - output_line[15:12];
  assign line_diff2 = next_line2[15:12] - output_line[15:12];
  
  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      output_line <= 21'h1000;
    else if (eof)
      output_line <= 21'h1000;
    else if (clk_en & ((line_addr == xlen) & line_wren & (in_state == in_new)
		       | line_end & (in_state == in_do)
		       | line_end & (in_state == in_flush)))
      output_line <= next_line;

  //---------------------------------------------------------------------------
  // Line buffer controls
  //---------------------------------------------------------------------------
  assign line_wren = clk_en & ~rgb_empty & ((in_state == in_idle)
					    | (in_state == in_line2)
					    | (in_state == in_new)
					    | (in_state == in_skip1)
					    | (in_state == in_skip2));
  wire rgb_rd = line_wren;
  
  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      line_addr <= 10'b0;
    else if (line_wren | clk_en & ((in_state == in_do)
				   | (in_state == in_flush)))
    begin
      if (line_end)
	line_addr <= 10'b0;
      else
	line_addr <= line_addr + 10'b1;
    end

  assign line_end = (line_addr == xlen);
  
  wire line_en = clk_en & (~rgb_empty & (in_state == in_new)
			   | (in_state == in_do)
			   | (in_state == in_flush));
  
  //---------------------------------------------------------------------------
  // Instantiate line buffer RAMs
  //
  // Quartus will only generate power of 2 depth memories but we require 768
  // words so three M4Ks are instantiated for each line buffer.
  //---------------------------------------------------------------------------
  wire 		line_wren0 = line_wren & (line_addr[9:8] == 2'b00);
  wire 		line_wren1 = line_wren & (line_addr[9:8] == 2'b01);
  wire 		line_wren2 = line_wren & (line_addr[9:8] == 2'b10);
  
  line_buffer_ram u_line2_0 (
			     .clock	(clk),
			     .wraddress	(line_addr[7:0]),
			     .wren	(line_wren0),
			     .data	(rgb_in),
			     
			     .rdaddress	(line_addr[7:0]),
			     .q		(line2_0_rdata)
			     );

  line_buffer_ram u_line2_1 (
			     .clock	(clk),
			     .wraddress	(line_addr[7:0]),
			     .wren	(line_wren1),
			     .data	(rgb_in),
			     
			     .rdaddress	(line_addr[7:0]),
			     .q		(line2_1_rdata)
			     );

  line_buffer_ram u_line2_2 (
			     .clock	(clk),
			     .wraddress	(line_addr[7:0]),
			     .wren	(line_wren2),
			     .data	(rgb_in),
			     
			     .rdaddress	(line_addr[7:0]),
			     .q		(line2_2_rdata)
			     );

  always @(line_addr or line2_0_rdata or line2_1_rdata or line2_2_rdata)
    case (line_addr[9:8])
      2'b00: line2_rdata = line2_0_rdata;
      2'b01: line2_rdata = line2_1_rdata;
      default: line2_rdata = line2_2_rdata;
    endcase

  line_buffer_ram u_line1_0 (
			     .clock	(clk),
			     .wraddress	(line_addr[7:0]),
			     .wren	(line_wren0),
			     .data	(line2_rdata),
			     
			     .rdaddress	(line_addr[7:0]),
			     .q		(line1_0_rdata)
			     );

  line_buffer_ram u_line1_1 (
			     .clock	(clk),
			     .wraddress	(line_addr[7:0]),
			     .wren	(line_wren1),
			     .data	(line2_rdata),
			     
			     .rdaddress	(line_addr[7:0]),
			     .q		(line1_1_rdata)
			     );

  line_buffer_ram u_line1_2 (
			     .clock	(clk),
			     .wraddress	(line_addr[7:0]),
			     .wren	(line_wren2),
			     .data	(line2_rdata),
			     
			     .rdaddress	(line_addr[7:0]),
			     .q		(line1_2_rdata)
			     );

  always @(line_addr or line1_0_rdata or line1_1_rdata or line1_2_rdata)
    case (line_addr[9:8])
      2'b00: line1_rdata = line1_0_rdata;
      2'b01: line1_rdata = line1_1_rdata;
      default: line1_rdata = line1_2_rdata;
    endcase
  
  //---------------------------------------------------------------------------
  // Instantiate Multipliers
  //
  // One each for red, green and blue for each line buffer. May eventually be
  // reduced by resource sharing.
  //---------------------------------------------------------------------------
  wire [12:0] 	line1_red;
  wire [12:0] 	line1_green;
  wire [12:0] 	line1_blue;
  wire [11:0] 	line2_red;
  wire [11:0] 	line2_green;
  wire [11:0] 	line2_blue;

  reg [5:0] 	line2_fraction;
  // delay to avoid problem with output_line changing
  always @(posedge clk or negedge reset_n)
    if (~reset_n)
      line2_fraction <= 6'b0;
    else
      line2_fraction <= output_line[11:6];
  
  wire [6:0] 	line1_fraction = 7'b1000000 - {1'b0, line2_fraction};
  
  // line 1 red
  mult6x7 u_mult_1r (
		     .clock	(clk),
		     
		     .dataa	(line1_rdata[17:12]),
		     .datab	(line1_fraction),
		     
		     .result	(line1_red)
		     );

  // line 1 green
  mult6x7 u_mult_1g (
		     .clock	(clk),
		     
		     .dataa	(line1_rdata[11:6]),
		     .datab	(line1_fraction),
		     
		     .result	(line1_green)
		     );

  // line 1 blue
  mult6x7 u_mult_1b (
		     .clock	(clk),
		     
		     .dataa	(line1_rdata[5:0]),
		     .datab	(line1_fraction),
		     
		     .result	(line1_blue)
		     );

  // line 2 red
  mult6x6 u_mult_2r (
		     .clock	(clk),
		     
		     .dataa	(line2_rdata[17:12]),
		     .datab	(line2_fraction),
		     
		     .result	(line2_red)
		     );

  // line 2 green
  mult6x6 u_mult_2g (
		     .clock	(clk),
		     
		     .dataa	(line2_rdata[11:6]),
		     .datab	(line2_fraction),
		     
		     .result	(line2_green)
		     );

  // line 2 blue
  mult6x6 u_mult_2b (
		     .clock	(clk),
		     
		     .dataa	(line2_rdata[5:0]),
		     .datab	(line2_fraction),
		     
		     .result	(line2_blue)
		     );

  wire [5:0] red_out = (line1_red + line2_red) >> 6;
  wire [5:0] green_out = (line1_green + line2_green) >> 6;
  wire [5:0] blue_out = (line1_blue + line2_blue) >> 6;

  wire [17:0] rgb_out = {red_out, green_out, blue_out};

  wire rgb_out_en = line_en;

endmodule	// yscale

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -