Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

Quartus 2 Analysis + Synthesis Takes Too Long

Hi all,

I'm creating an 8-bit game for a university comp sci assignment (so, I have a good amount of programming experience, but not with hardware description languages) using a Cyclone 2, Quartus 2, and verilog and I'm having some real difficulty with the compile time.

My program consists of 3 modules: a VGADriver (which takes input from the frame_buffer and displays it on screen), a controller driver (which polls a gamepad and sends the results to controller_buffer), and a gameplay module (shown below). It normally takes 1.5-2 minutes to compile, but when I add the following lines of code to the gameplay module, it takes over an hour, and it runs out of memory before it finishes compiling:


            if((controller_buffer) && (player_1_pos  > 0)) begin
                player_1_pos = player_1_pos - 1;
            end
            if((controller_buffer) && (player_1_pos  < (frame_line_size - (player_1_length * 2)))) begin
                player_1_pos = player_1_pos + 1;
            end
The code essentially moves the player 1 pixels left or right based on controller D-pad input.

And here are the messages that I get during the hour compilation (it gets stuck for an hour between the 'Info:' and 'Error:' lines):

Info: Elaborating entity "Gameplay" for hierarchy "Gameplay:game"

Error: Out of memory in module quartus_map.exe (3205 megabytes used)

Error: Current module quartus_map ended unexpectedly

Here's the entire gameplay module with the problem section tagged:


module Gameplay (
input clk,
output reg  frame_buffer,
input  controller_buffer
); 
    //constants for the controller buttons
    parameter num_buttons = 8;
    parameter LEFTPAD = 5;
    parameter RIGHTPAD = 7;
    
    //frame buffer size constants
    parameter frame_buffer_size = 3600;
    parameter frame_line_size = 120;
    parameter colour_depth = 3;
    parameter RED_INDEX = 0;
    parameter BLUE_INDEX = 1;
    parameter GREEN_INDEX = 2;
    parameter BLACK = 3'b000;
    parameter GREEN = 3'b100;
    
    //player 1 position constants
    parameter player_1_length = 7;
    parameter player_1_height = 4;
    parameter player_1_start_x = ((frame_line_size/colour_depth)/2) - (player_1_length/2);
    parameter player_1_y = 0;
    reg  player_1_pos;
    reg  poll_count;
    
    initial begin
        //initialize the frame buffer to all black
        frame_buffer = 0;
        player_1_pos = player_1_start_x;
        poll_count = 0;
    end
    
    always @(negedge clk) begin
        //poll the controller for button pressed every million clock cycles
        poll_count = poll_count + 1;
        if(poll_count >= 1000000) begin
            draw_player_1_pos;
            poll_count = 0;
        end
    end
    
    //re-draws player 1 on the screen based on D-pad button inputs and the current position of player 1
    task draw_player_1_pos;
        begin
            draw_player_1(player_1_pos, player_1_y, BLACK);
            //HERE'S WHERE THE PROBLEM BEGINS
            if((controller_buffer) && (player_1_pos > 0)) begin
                player_1_pos = player_1_pos - 1;
            end
            if((controller_buffer) && (player_1_pos < (frame_line_size - (player_1_length * 2)))) begin
                player_1_pos = player_1_pos + 1;
            end
            //HERE'S WHERE THE PROBLEM ENDS
            draw_player_1(player_1_pos, player_1_y, GREEN);
        end
    endtask
    
    //draws player 1 on the screen
    task draw_player_1;
    input  x;
    input  y;
    input  colour;
        begin
            set_pixel(x + 3, y, colour);
            
            set_pixel(x + 2, y + 1, colour);
            set_pixel(x + 3, y + 1, colour);
            set_pixel(x + 4, y + 1, colour);
            
            set_pixel(x, y + 2, colour);
            set_pixel(x + 1, y + 2, colour);
            set_pixel(x + 2, y + 2, colour);
            set_pixel(x + 3, y + 2, colour);
            set_pixel(x + 4, y + 2, colour);
            set_pixel(x + 5, y + 2, colour);
            set_pixel(x + 6, y + 2, colour);
            
            set_pixel(x, y + 3, colour);
            set_pixel(x + 1, y + 3, colour);
            set_pixel(x + 2, y + 3, colour);
            set_pixel(x + 3, y + 3, colour);
            set_pixel(x + 4, y + 3, colour);
            set_pixel(x + 5, y + 3, colour);
            set_pixel(x + 6, y + 3, colour);
        end
    endtask
    
    //display a pixel on the screen when given an x coordinate, y coordinate, and colour for the pixel
    task set_pixel;
    input  x_coordinate;
    input  y_coordinate;
    input  colour;
    reg  pixel_pos;
        begin
            pixel_pos = ((((frame_buffer_size/frame_line_size) - y_coordinate) * frame_line_size) - (x_coordinate * colour_depth)) - 1;
            frame_buffer = colour;
            frame_buffer = colour;
            frame_buffer = colour;
        end
    endtask
endmodule
If you have any idea at all on how to solve my problem, please don't hesitate to reply. I really need some help here. Thanks so much.

6 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Try to move part of the code into a concurent statement. Something like this:

    assign aux = frame_line_size - (player_1_length << 1);

    And then rewrite your code as:

    if((controller_buffer[RIGHTPAD]) && (player_1_pos < aux)) begin

    player_1_pos = player_1_pos + 1;

    end
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I have a good amount of programming experience, but not with hardware description languages

    --- Quote End ---

    Obviously. The design is effectively not synthesizable, because the complexity of set_pixel actions exceeds the logic resources of any available FPGA. It doesn't work this way.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    FvM, previously I did not look into the code in detail. Now that I did, I agree with you.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Try to move part of the code into a concurent statement. Something like this:

    assign aux = frame_line_size - (player_1_length << 1);

    And then rewrite your code as:

    if((controller_buffer[RIGHTPAD]) && (player_1_pos < aux)) begin

    player_1_pos = player_1_pos + 1;

    end

    --- Quote End ---

    Naa, it doesn't seem to work. Thanks anyways.

    --- Quote Start ---

    Obviously. The design is effectively not synthesizable, because the complexity of set_pixel actions exceeds the logic resources of any available FPGA. It doesn't work this way.

    --- Quote End ---

    I think this is my problem. I guess I'll have to spread the work across several clock cycles. But, the odd thing is that when I replace this code that just increments/decrements based on a buffer flag:

    if((controller_buffer[LEFTPAD]) && (player_1_pos > 0)) begin

    player_1_pos <= player_1_pos - 1;

    end

    if((controller_buffer[RIGHTPAD]) && (player_1_pos < (frame_line_size - (player_1_length * 2)))) begin

    player_1_pos <= player_1_pos + 1;

    end

    with something like this that does a lot more processing:

    draw_player_1(player_1_pos, player_1_y + 20, GREEN);

    it compiles in 3 minutes, while the former code eventually runs out of memory after an hour. I guess the compiler is doing a lot more background work on the first block of code than the second block of code that I am not aware of.

    Thanks for your response.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Without the block that changes player_1_pos, your design's output is constant and can be determined during compilation.

    The synthesis tool is able to recognize that and optimizes everything away.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Without the block that changes player_1_pos, your design's output is constant.

    --- Quote End ---

    Yes, exactly.

    --- Quote Start ---

    I guess I'll have to spread the work across several clock cycles.

    --- Quote End ---

    That's definitely the way to go. In addition, you should think about how to represent your frame buffer. Now it's a huge block of registers. I fear, that the design still won't fit a reasonable FPGA size, because a graveyard of multiplexers is required to access each framebuffer element, even with the presently used coarse resolution. In practice, an addressable memory, either external or internal RAM, is the only feasible way to design a frame buffer. It restricts frame buffer access to sequential methods, of course.