I'm trying to use a buffer to make the animation smoother in my current project. I was able to implement it properly without buffers with the player character moving smoothly. But for some reason with this implementation the player character only moves like once in 5 to 10 seconds.
I tried simulating and looking at the waves but so far the waves seem find and does not explain why the screen is refreshing slowly. It refreshes slow but it is drawn perfectly without any flashing.
Here is the code for buffer that is probably causing the problem,
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
And one more thing, the background is supposed to be white because I input 111111111111 into VGA when not drawing the player but for some reason the screen is blue. I'm not sure what's causing it either.
Okay. I somehow solved it by myself again. It turns out that the clock frequency for the VRAM has to match the display in order to work properly. Not it's working so smoothly that its unbelievable!
Also, found out why the background was turning blue. I forgot that I reduced the data width for my VRAM because I ran out of MUX. So basically, the VRAM was only outputting 4 bits and that was the cause of the blue background.