Verilog VGA缓冲区无法正常工作

时间:2018-11-07 08:33:16

标签: buffer verilog fpga vga

我正在尝试使用缓冲区使当前项目中的动画更加平滑。 我能够在没有缓冲的情况下正确实现它,并且玩家角色可以平稳移动。但是由于某种原因,玩家角色只能在5到10秒内移动一次。

我尝试模拟并查看海浪,但到目前为止,海浪似乎已经发现,并且无法解释屏幕刷新缓慢的原因。刷新速度很慢,但是绘制得很完美,没有任何闪烁。

这是可能导致问题的缓冲区代码,

module m_engine
(
  input  wire        CLK100MHZ,
  input  wire [4:0]  BTN,
  input  wire [15:0] SW,
  output wire [6:0]  SG,
  output wire [7:0]  AN,
  output wire [15:0] LED,
  output wire        VGA_HS,
  output wire        VGA_VS,
  output reg  [3:0]  VGA_R,
  output reg  [3:0]  VGA_G,
  output reg  [3:0]  VGA_B
);
  /****************************************************************************/
  // Simulation
  /****************************************************************************/
  // reg CLK100MHZ = 0, r_display_clock = 0;
  // initial forever #1 CLK100MHZ = ~CLK100MHZ;
  // initial forever #2 r_display_clock = ~r_display_clock;
  //
  // assign w_display_clock = r_display_clock;
  /****************************************************************************/

  /****************************************************************************/
  // Display
  /****************************************************************************/
  wire        w_display_clock;
  wire [10:0] w_display_x;
  wire [10:0] w_display_y;
  wire        w_display_active;
  wire        w_display_reset;
  wire        w_display_frame;
  reg  [11:0] r_display_out;

  CLK40MHZ display_clock (w_display_clock, CLK100MHZ);
  assign w_display_reset = SW[15];
  always @ (posedge CLK100MHZ)
  begin
    if (w_display_active)
    begin
      VGA_R <= r_display_out[11:8];
      VGA_G <= r_display_out[7:4];
      VGA_B <= r_display_out[3:0];
    end
    else
    begin
      VGA_R <= 0;
      VGA_G <= 0;
      VGA_B <= 0;
    end
  end

  m_vga display
  (
    .iw_clock  (w_display_clock),
    .iw_rst    (w_display_reset),
    .ow_hs     (VGA_HS),
    .ow_vs     (VGA_VS),
    .ow_x      (w_display_x),
    .ow_y      (w_display_y),
    .ow_active (w_display_active),
    .ow_frame  (w_display_frame)
  );
  /****************************************************************************/

  /****************************************************************************/
  // VRAM
  /****************************************************************************/
  localparam DISPLAY_WIDTH   = 800;
  localparam DISPLAY_HEIGHT  = 600;
  localparam VRAM_DEPTH      = DISPLAY_WIDTH * DISPLAY_HEIGHT;
  localparam VRAM_ADDR_WIDTH = 19;
  localparam VRAM_DATA_WIDTH = 4;

  reg  [VRAM_ADDR_WIDTH - 1:0] r_vram_address;
  wire [VRAM_DATA_WIDTH - 1:0] w_vram0_dataout, w_vram1_dataout;
  reg  [VRAM_DATA_WIDTH - 1:0] r_vram_datain;
  reg                          r_vram_write = 0;

  always @(posedge CLK100MHZ)
  begin
    r_vram_address <= w_display_y * DISPLAY_WIDTH + w_display_x;
    // Display content of active VRAM
    r_display_out = (r_vram_write) ? w_vram1_dataout : w_vram0_dataout;
  end

  // At the end of every frame switch buffers.
  always @(posedge w_display_frame)
    r_vram_write = ~r_vram_write;

  m_sram
  #(
    .ADDR_WIDTH (VRAM_ADDR_WIDTH),
    .DATA_WIDTH (VRAM_DATA_WIDTH),
    .DEPTH      (VRAM_DEPTH)
  )
  vram0
  (
    .iw_addr  (r_vram_address),
    .iw_clock (CLK100MHZ),
    .iw_write (r_vram_write),
    .or_data  (w_vram0_dataout),
    .iw_data  (r_vram_datain)
  );

  m_sram
  #(
    .ADDR_WIDTH (VRAM_ADDR_WIDTH),
    .DATA_WIDTH (VRAM_DATA_WIDTH),
    .DEPTH      (VRAM_DEPTH)
  )
  vram1
  (
    .iw_addr  (r_vram_address),
    .iw_clock (CLK100MHZ),
    .iw_write (!r_vram_write),
    .or_data  (w_vram1_dataout),
    .iw_data  (r_vram_datain)
  );
  /****************************************************************************/

  /****************************************************************************/
  // Game Logic
  /****************************************************************************/
  reg [10:0] r_player_x = 400, r_player_y = 300;
  wire w_player_draw;
  wire [VRAM_DATA_WIDTH - 1:0] w_player_dataout;

  m_entity
  #(
    .ADDR_WIDTH  (VRAM_ADDR_WIDTH),
    .DATA_WIDTH  (VRAM_DATA_WIDTH),
    .ENTITY_SIZE (32),
    .MEMFILE("fighter.mem")
  )
  player
  (
    .iw_clock  (CLK100MHZ),
    .iw_draw_x (w_display_x),
    .iw_draw_y (w_display_y),
    .iw_pos_x  (r_player_x),
    .iw_pos_y  (r_player_y),
    .ow_draw   (w_player_draw),
    .or_data   (w_player_dataout)
  );

  reg [11:0] r_player_palette [0:255];
  initial
  begin
    $display("Loading sprite r_player_palette.");
    $readmemh("fighter_palette.mem", r_player_palette);
  end

  reg [20:0] r_i = 0;
  always @(posedge CLK100MHZ)
  begin
    // Player control
    r_i <= r_i + 1;
    if(r_i == 0)
    begin
      if (BTN[3] && r_player_x < DISPLAY_WIDTH - 32)
        r_player_x <= r_player_x + 1;
      if (BTN[2] && r_player_x > 0)
        r_player_x <= r_player_x - 1;
      if (BTN[4] && r_player_y < DISPLAY_HEIGHT - 32)
        r_player_y <= r_player_y + 1;
      if (BTN[1] && r_player_y > 0)
        r_player_y <= r_player_y - 1;
    end

    // Player draw
    if      (w_player_draw) r_vram_datain <= w_player_dataout;
    else                    r_vram_datain <= 12'b111111111;
  /****************************************************************************/
endmodule

还有一件事,背景应该是白色的,因为当我不绘制播放器但由于某种原因屏幕是蓝色时,我将111111111111输入到VGA中。我也不知道是什么原因造成的。

1 个答案:

答案 0 :(得分:0)

好的。我又以某种方式自己解决了。事实证明,VRAM的时钟频率必须与显示器匹配才能正常工作。不是它的运行如此平稳以至于令人难以置信!

还找出了背景为何变成蓝色的原因。我忘了我减少了VRAM的数据宽度,因为我用完了MUX。因此,基本上,VRAM仅输出4位,这就是蓝色背景的原因。