Verilog VGA буфер не работает как положено - PullRequest
0 голосов
/ 07 ноября 2018

Я пытаюсь использовать буфер, чтобы сделать анимацию более плавной в моем текущем проекте. Я смог реализовать это должным образом без буферов, когда персонаж игрока двигался плавно. Но по какой-то причине в этой реализации персонаж игрока перемещается только раз в 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 голосов
/ 07 ноября 2018

Хорошо. Я как-то снова решил это сам. Оказывается, что для правильной работы тактовая частота VRAM должна соответствовать дисплею. Не работает так гладко, что это невероятно!

Также выяснил, почему фон стал синим. Я забыл, что я уменьшил ширину данных для моей VRAM, потому что у меня закончился MUX. В общем, VRAM выводил только 4 бита, и это было причиной синего фона.

...