Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

A question about programming FPGA's in C

Posted on 2010-11-16
16
1,045 Views
Last Modified: 2013-11-13
Hey,

       I'm trying to write a Snake game on an FPGA board, I have a simple program that has a moves a block across the screen.

The problems I'm having are:
- Separating the VHDL code to draw the Snake and apple separately
- Increasing the length of the Snake
- Keeping the existing image on the screen and drawing a new image

This is what I have so far:

Appreciate any help on this.
#include "xparameters.h"

#include "stdio.h"

#include "xbasic_types.h"
#include "xgpio.h"
#include "gpio_header.h"
#include "uartlite_header.h"

/* Added for VGA peripheral */
#include "vga.h"


//====================================================

int main (void) {

   /*
    * Enable and initialize cache
    */
   #if XPAR_MICROBLAZE_0_USE_ICACHE
      microblaze_init_icache_range(0, XPAR_MICROBLAZE_0_CACHE_BYTE_SIZE);
      microblaze_enable_icache();
   #endif

   #if XPAR_MICROBLAZE_0_USE_DCACHE
      microblaze_init_dcache_range(0, XPAR_MICROBLAZE_0_DCACHE_BYTE_SIZE);
      microblaze_enable_dcache();
   #endif

   print("-- Entering main() --\r\n");

   /*
    * Peripheral SelfTest will not be run for RS232_DCE
    * because it has been selected as the STDOUT device
    */

   {
      Xuint32 status;
      
      print("\r\nRunning GpioOutputExample() for LEDs_8Bit...\r\n");

      status = GpioOutputExample(XPAR_LEDS_8BIT_DEVICE_ID,8);
      
      if (status == 0) {
         print("GpioOutputExample PASSED.\r\n");
      }
      else {
         print("GpioOutputExample FAILED.\r\n");
      }
   }


   {
      Xuint32 status;
      
      print("\r\nRunning GpioInputExample() for Buttons_4Bit...\r\n");

      Xuint32 DataRead;
      
      status = GpioInputExample(XPAR_BUTTONS_4BIT_DEVICE_ID, &DataRead);
		
		/* Print the value read from pushbuttons*/
		putnum (DataRead);
		print("\r\n");
		putnum (rand());
		print("\r\n");
      
      if (status == 0) {
         xil_printf("GpioInputExample PASSED. Read data:0x%X\r\n", DataRead);
      }
      else {
         print("GpioInputExample FAILED.\r\n");
      }
   }


   {
      XStatus status;
      
      print("\r\nRunning UartLiteSelfTestExample() for debug_module...\r\n");
      status = UartLiteSelfTestExample(XPAR_DEBUG_MODULE_DEVICE_ID);
      if (status == 0) {
         print("UartLiteSelfTestExample PASSED\r\n");
      }
      else {
         print("UartLiteSelfTestExample FAILED\r\n");
      }
   }
   /*
    * Disable cache and reinitialize it so that other
    * applications can be run with no problems
    */
   #if XPAR_MICROBLAZE_0_USE_DCACHE
      microblaze_disable_dcache();
      microblaze_init_dcache_range(0, XPAR_MICROBLAZE_0_DCACHE_BYTE_SIZE);
   #endif

   #if XPAR_MICROBLAZE_0_USE_ICACHE
      microblaze_disable_icache();
      microblaze_init_icache_range(0, XPAR_MICROBLAZE_0_CACHE_BYTE_SIZE);
   #endif

	{
	/* added for VGA */
   Xuint32 objects_array[4];
	Xuint32 ball[4];
	
	/*
	* The following constant is used to wait each time around the loop. 
	* This constant might need to be tuned for faster or slower processor speeds.
	*/
	#define GAME_DELAY     10000

	/* Added for pushbutton input */
	Xuint32 DataRead;
	Xuint32 PrevRead;
	
	Xuint32 Status;
	XGpio GpioInput;
	
   volatile int Delay;

   Status = XGpio_Initialize(&GpioInput, XPAR_BUTTONS_4BIT_DEVICE_ID);
   if (Status != XST_SUCCESS)
		{
		print("PANIC! Gpio Initialize FAILED.\r\n");
		}

    /*
     * Set the direction for all signals to be inputs
     */
    XGpio_SetDataDirection(&GpioInput, 1, 0xFFFFFFFF);

	 //Initialize your input data over here: 
	 objects_array[0] = 320; // x coordinate for ball     
	 objects_array[1] = 240; // y coordinate for ball    
	 objects_array[2] = 300; // x coordinate for bar    
	 objects_array[3] = 220; // y coordinate for bar 
	 ball[0] = 500; // x coordinate for bar    
	 ball[1] = 100; // y coordinate for bar 	 
	 ball[2] = 250;
	 ball[3] = 350;

	 while (1) {

		//Call the FSL peripheral to display game objects
		vga(XPAR_FSL_VGA_0_INPUT_SLOT_ID, ball);
		vga(XPAR_FSL_VGA_0_INPUT_SLOT_ID, objects_array);
		
		// Get new ball position based on user input
		DataRead = XGpio_DiscreteRead(&GpioInput, 1);
		
		
		if(DataRead == 0) {
			if (PrevRead == 1) { // Down button
			objects_array[3] = objects_array[3]+1;
			}
			if (PrevRead == 2) { // Up button
			objects_array[3] = objects_array[3]-1;
			}
			if (PrevRead == 4) { // Right button
			objects_array[2] = objects_array[2]+1;
			}
			if (PrevRead == 8) { // Right button
			objects_array[2] = objects_array[2]-1;
			}
		}
		
		
		if (DataRead == 1) { // Down button
			objects_array[3] = objects_array[3]+1;
			}
		if (DataRead == 2) { // Up button
			objects_array[3] = objects_array[3]-1;
			}
		if (DataRead == 4) { // Right button
			objects_array[2] = objects_array[2]+1;
			}
		if (DataRead == 8) { // Right button
			objects_array[2] = objects_array[2]-1;
			}
		
		if(DataRead != 0) {
			PrevRead = DataRead;
		}
		
		// Bar moves around randomly
		objects_array[0] = objects_array[0];
		objects_array[1] = objects_array[1];

		// If the ball catches up to the randomly moving bar, game is WON!
		if ((objects_array[0]==objects_array[2]) && (objects_array[1]==objects_array[3]))
			{
			print("YOU WON!\r\n");
			GpioOutputExample(XPAR_LEDS_8BIT_DEVICE_ID,8); // Go blink the LEDS!
			}
		
		/* Wrap the ball object around the screen */
		if (objects_array[0] == 0) objects_array[0] = 639-8;
		if (objects_array[1] == 0) objects_array[1] = 479-8;
		objects_array[0] = objects_array[0] % 640;
		objects_array[1] = objects_array[1] % 480;

		/* Wrap the bar object around the screen */
		if (objects_array[2] == 0) objects_array[2] = 639-8;
		if (objects_array[3] == 0) objects_array[3] = 479-8;
		objects_array[2] = objects_array[2] % 640;
		objects_array[3] = objects_array[3] % 480;

		/*
       * Wait a small amount of time or the ball will move too fast!
       */
      for (Delay = 0; Delay < GAME_DELAY*5; Delay++);		
	   }
	 }

   print("-- Exiting main() --\r\n");
   return 0;
}

========================================================


-- Created by Dr. K 11/29/08
-- Display buffer for VGA screen for 2 object game

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity vga_buffer is
   generic (OBJECT_SIZE : natural := 10);
   port(
        video_on: in std_logic;
        pixel_x, pixel_y : in std_logic_vector(0 to OBJECT_SIZE-1);
        object1x, object1y : in std_logic_vector(0 to OBJECT_SIZE-1);
        object2x, object2y : in std_logic_vector(0 to OBJECT_SIZE-1);
        graph_rgb: out std_logic_vector(0 to 2)
   );
end vga_buffer;

architecture arch of vga_buffer is
   ----------------------------------------------
   -- stationary object - vertical strip as a wall
   ----------------------------------------------
   -- wall left, right boundary
   constant WALL_X_L: integer:=32;
   constant WALL_X_R: integer:=35;
  ----------------------------------------------
   -- 1st game object - a square bar
   ----------------------------------------------
   -- bar left, right boundary
   constant BAR_SIZE: integer:=16;
   ----------------------------------------------
   -- 2nd game object - round ball image ROM
   ----------------------------------------------
   constant BALL_SIZE: integer:=8;
   type rom_type is array (0 to 7)
        of std_logic_vector(0 to 7);
   -- ROM definition
   constant BALL_ROM: rom_type :=
   (
      "00111100", --   ****
      "01111110", --  ******
      "11111111", -- ********
      "11111111", -- ********
      "11111111", -- ********
      "11111111", -- ********
      "01111110", --  ******
      "00111100"  --   ****
   );
   signal rom_addr, rom_col: unsigned(0 to 2);
   signal rom_data: std_logic_vector(0 to 7);
   signal rom_bit: std_logic;
   ----------------------------------------------

   -- x, y coordinates of the ball
   signal ball_x_l : unsigned (0 to OBJECT_SIZE-1);
   signal ball_y_t : unsigned (0 to OBJECT_SIZE-1);
   signal ball_x_r : unsigned (0 to OBJECT_SIZE-1);
   signal ball_y_b : unsigned (0 to OBJECT_SIZE-1);

   -- x, y coordinates of the bar
   signal bar_x_l : unsigned (0 to OBJECT_SIZE-1);
   signal bar_y_t : unsigned (0 to OBJECT_SIZE-1);
   signal bar_x_r : unsigned (0 to OBJECT_SIZE-1);
   signal bar_y_b : unsigned (0 to OBJECT_SIZE-1);

   -- x, y coordinates (0,0) to (639,479)
   signal pix_x, pix_y: unsigned(0 to OBJECT_SIZE-1);
   constant MAX_X: integer:=640;
   constant MAX_Y: integer:=480;

   ----------------------------------------------
   -- object output signals
   ----------------------------------------------
   signal wall_on, bar_on, sq_ball_on, rd_ball_on: std_logic;
   signal wall_rgb, bar_rgb, ball_rgb:
          std_logic_vector(0 to 2);

begin
   pix_x <= unsigned(pixel_x);
   pix_y <= unsigned(pixel_y);
   ----------------------------------------------
   -- Constant object - (wall) left vertical strip
   ----------------------------------------------
   -- pixel within wall
   wall_on <=
      '1' when (WALL_X_L<=pix_x) and (pix_x<=WALL_X_R) else
      '0';
   -- wall rgb output
   wall_rgb <= "001"; -- blue
   ----------------------------------------------
   -- 1st game object - a red ball
   ----------------------------------------------
   -- boundary
   ball_x_l <= unsigned(object1x);
   ball_y_t <= unsigned(object1y);
   ball_x_r <= ball_x_l + BALL_SIZE - 1;
   ball_y_b <= ball_y_t + BALL_SIZE - 1;
   -- pixel within ball
   sq_ball_on <=
      '1' when (ball_x_l<=pix_x) and (pix_x<=ball_x_r) and
               (ball_y_t<=pix_y) and (pix_y<=ball_y_b) else
      '0';
   -- map current pixel location to ROM addr/col
   rom_addr <= pix_y(7 to 9) - ball_y_t(7 to 9);
   rom_col <= pix_x(7 to 9) - ball_x_l(7 to 9);
   rom_data <= BALL_ROM(to_integer(rom_addr));
   rom_bit <= rom_data(to_integer(rom_col));
   -- pixel within ball
   rd_ball_on <=
      '1' when (sq_ball_on='1') and (rom_bit='1') else
      '0';
   -- ball rgb output
   ball_rgb <= "100";   -- red
   ----------------------------------------------
   -- 2nd game object - a square bar
   ----------------------------------------------
   -- pixel within bar
   bar_x_l <= unsigned(object2x);
   bar_y_t <= unsigned(object2y);
   bar_x_r <= bar_x_l + BAR_SIZE - 1;
   bar_y_b <= bar_y_t + BAR_SIZE - 1;
   bar_on <=
      '1' when (BAR_X_L<=pix_x) and (pix_x<=BAR_X_R) and
               (bar_y_t<=pix_y) and (pix_y<=bar_y_b) else
      '0';
   -- bar rgb output
   bar_rgb <= "010"; --green
   ----------------------------------------------
   -- rgb multiplexing circuit
   ----------------------------------------------
   process(video_on,wall_on,bar_on,sq_ball_on,
           wall_rgb, bar_rgb, ball_rgb)
   begin
      if video_on='0' then
          graph_rgb <= "000"; --blank
      else
         if wall_on='1' then
            graph_rgb <= wall_rgb;
         elsif bar_on='1' then
            graph_rgb <= bar_rgb;
         elsif rd_ball_on='1' then
            graph_rgb <= ball_rgb;
         else
            graph_rgb <= "000"; -- black background
         end if;
      end if;
   end process;
end arch;

========================================================

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity vga is
	port 
	(
		-- DO NOT EDIT BELOW THIS LINE ---------------------
		-- Bus protocol ports, do not add or delete. 
		FSL_Clk	: in	std_logic;
		FSL_Rst	: in	std_logic;
		FSL_S_Clk	: out	std_logic;
		FSL_S_Read	: out	std_logic;
		FSL_S_Data	: in	std_logic_vector(0 to 31);
		FSL_S_Control	: in	std_logic;
		FSL_S_Exists	: in	std_logic;
		-- DO NOT EDIT ABOVE THIS LINE ---------------------
		
		-- Added by DrK to implement VGA port pins 11/29/08
		hsync: out  std_logic;
		vsync: out  std_logic;
    rgb:   out std_logic_vector(0 to 2)
	);

attribute SIGIS : string; 
attribute SIGIS of FSL_Clk : signal is "Clk"; 
attribute SIGIS of FSL_S_Clk : signal is "Clk"; 
end vga;

------------------------------------------------------------------------------
-- Architecture Section
------------------------------------------------------------------------------

-- In this section, we povide an example implementation of ENTITY vga
-- that Read all inputs and add each input to the contents of register 'sum' which
-- acts as an accumulator
--
-- You will need to modify this example or implement a new architecture for
-- ENTITY vga to implement your coprocessor

architecture EXAMPLE of vga is

component vga_top is
    generic (OBJECT_SIZE : natural := 10);
    port (
      clk, reset: in std_logic;
      object1x : in std_logic_vector(0 to OBJECT_SIZE-1);
      object1y : in std_logic_vector(0 to OBJECT_SIZE-1);
      object2x : in std_logic_vector(0 to OBJECT_SIZE-1);
      object2y : in std_logic_vector(0 to OBJECT_SIZE-1);
      hsync, vsync: out  std_logic;
      rgb: out std_logic_vector(0 to 2)
   );
end component;

   -- Added by Dr.K to track X,Y position of game objects
   -- This game has two objects and position will not exceed 1023
   -- because VGA screen resolution is 640x480. 10/29/08
   constant OBJECT_SIZE : natural := 10; -- max. coordinate value is 1024
   subtype OBJECT is STD_LOGIC_VECTOR (0 to OBJECT_SIZE-1);
   constant OBJECTS_SIZE : natural := 4; -- this game has 2 objects (i.e. 2 xy-pairs)
   type OBJECTS is array (0 to OBJECTS_SIZE-1) of OBJECT;  
   signal objects_array, objects_array_todisplay : OBJECTS;

   -- This is used to signal loading the objects for display
   signal objects_done : std_logic;
   
   -- Total number of input data.
   constant NUMBER_OF_INPUT_WORDS  : natural := 4;

   type STATE_TYPE is (Idle, Read_Inputs);

   signal state        : STATE_TYPE;

   -- Counters to store the number inputs read
   signal nr_of_reads  : natural range 0 to NUMBER_OF_INPUT_WORDS - 1;

begin
   -- CAUTION:
   -- The sequence in which data are read in should be
   -- consistent with the sequence they are written in the
   -- driver's vga.c file

   FSL_S_Read  <= FSL_S_Exists   when state = Read_Inputs   else '0';
   The_SW_accelerator : process (FSL_Clk) is
   begin  -- process The_SW_accelerator
    if FSL_Clk'event and FSL_Clk = '1' then     -- Rising clock edge
      if FSL_Rst = '1' then               -- Synchronous reset (active high)
        -- CAUTION: make sure your reset polarity is consistent with the
        -- system reset polarity
        state        <= Idle;
        nr_of_reads  <= 0;
        objects_array <= (OTHERS => (OTHERS => '0'));
        objects_done <= '0';
      else
        case state is
          when Idle =>
            if (FSL_S_Exists = '1') then
              state       <= Read_Inputs;
              nr_of_reads <= NUMBER_OF_INPUT_WORDS - 1;
              objects_done <= '0';
            end if;

          when Read_Inputs =>
            if (FSL_S_Exists = '1') then
              -- Save object position
              objects_array(nr_of_reads) <= FSL_S_Data (22 to 31);
              if (nr_of_reads = 0) then
                objects_done <= '1';              
                state        <= Idle;
              else
                objects_done <= '0';              
                nr_of_reads <= nr_of_reads - 1;
              end if;
            end if;

        end case;
      end if;
    end if;
   end process The_SW_accelerator;
   
   -- Process to copy object positions to buffer that gets displayed...
   COPY_OBJECTS: process (FSL_Clk) is
   begin
    if FSL_Clk'event and FSL_Clk = '1' then     -- Rising clock edge
      if FSL_Rst = '1' then               -- Synchronous reset (active high)
        -- CAUTION: make sure your reset polarity is consistent with the
        -- system reset polarity
        objects_array_todisplay <= (OTHERS => (OTHERS => '0'));
      elsif objects_done = '1' then
        objects_array_todisplay <= objects_array;
      end if;
    end if;
   end process;

   -- Instance the VGA component
   GAME_TOP_U1: vga_top generic map (OBJECT_SIZE=>OBJECT_SIZE)
   port map (
    clk => FSL_Clk,
    reset => FSL_Rst,
    object1x => objects_array_todisplay(3),
    object1y => objects_array_todisplay(2),
    object2x => objects_array_todisplay(1),
    object2y => objects_array_todisplay(0),
    hsync => hsync,
    vsync => vsync,
    rgb => rgb
    );

end architecture EXAMPLE;

=========================================================

Open in new window

0
Comment
Question by:errang
  • 6
  • 6
  • 3
16 Comments
 
LVL 12

Expert Comment

by:HappyCactus
ID: 34162386
Errang,

it is not clear what you need. Your requests are very generic, it seems to me that they do not relate to C.
Can you be more precise?
0
 

Author Comment

by:errang
ID: 34164559
Well, one of the main problem I'm facing is duplicating an array in C.

I get the contents for the array from the VHDL files, and it seems kinda fixated on keeping that array as it is.
0
 
LVL 12

Expert Comment

by:HappyCactus
ID: 34165062
VHDL files? I do not understand this concept.
VHDL is compilated and the firmware transferred to the FPGA chip.
The code is executed by the FPGA.
How is the data transferred from and to the FPGA?
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 

Author Comment

by:errang
ID: 34166810
>>How is the data transferred from and to the FPGA?
We're using the EDK tool provided by Xilinx to do this.

The VHDL files are the graphics drivers.
0
 
LVL 12

Assisted Solution

by:HappyCactus
HappyCactus earned 150 total points
ID: 34166904
sorry, I think we misunderstood.
you told: "I get the contents for the array from the VHDL files, and it seems kinda fixated on keeping that array as it is."
What do you mean that you want to change it? What array are you speaking about?
If you mean you want to change the array dynamically from the C file, you have to implement the access to the array on the FPGA via some kind of interface.
If you mean you want to change something on the fpga code, you must change it on the source, because as you can see, they are defined as code, not a block of data.
But it's not clear to me what is your problem, frankly.
0
 
LVL 20

Expert Comment

by:ikework
ID: 34169025
If you want to manipulate some hardcoded data, then you need some kind of memory chip connected to the FPGA where you copy the data to and manipulate it. Do you have a memory-chip on the FPGAs board?
0
 

Author Comment

by:errang
ID: 34169071
We do have some flash memory on the board...

But, my main question is this:

The VHDL files are passing some object into the Xuint32 objects_array[4];

And arrays are just pointers to blocks of data in memory somewhere, so what I wanted to know was, is it possible to say something like:

Xunit32 obj1 = objects_array[0];
Xunit32 obj2 = objects_array[1];

Xunit32 new_array[2];

new_array[0] = obj1;
new_array[1] = obj2;

To create a new object that is separate from the first object?

My logic is that the C program has access to the memory somewhere, so it "should" be able to manipulate it by accessing that block and making copies of it.

But... my logic didn't transfer over so well, so I just wanted to know if it was possible, or if I was climbing up the wrong wall.
0
 
LVL 12

Expert Comment

by:HappyCactus
ID: 34170758
"Where" the C code is run? Where is the CPU? How the CPU is connected to the FPGA and the RAM/Flash?
0
 
LVL 20

Expert Comment

by:ikework
ID: 34170852
@HappyCactus: there is no traditional CPU, the programm is compiled to a hardware-description language (HDL) represented by a gate-array configuration and burned to the FPGA:

http://en.m.wikipedia.org/wiki/Field-programmable_gate_array?wasRedirected=true
0
 
LVL 20

Accepted Solution

by:
ikework earned 350 total points
ID: 34171221
Yes, you can copy the array, you dont even need a temporary variable. You can use a loop, I assume here you have a variable storing the number of items to copy called "numItems". Then you can use either a loop:

    for(Xunit32 i = 0; i < numItems; ++i)
    {
        new_array[i] = objects_array[i];
    }

Open in new window


Or if your compiler supports memcpy, then you can use:

    Explanation of c-libaray memcpy

    memcpy((void*)new_array, (const void*)objects_array, numItems * sizeof(Xunit32));

Open in new window


ike
0
 
LVL 12

Expert Comment

by:HappyCactus
ID: 34172489
ikework, I know what an fpga is, i didn't know that the fpga could be programmed in C. As I seems to understand, the CPU is a soft core inside the FPGA. This I wanted to know.

Regards
0
 

Author Comment

by:errang
ID: 34172728
uh... meant to distribute the points 350 and 150 between the both of you... my bad, is there any way to fix this?
0
 
LVL 12

Expert Comment

by:HappyCactus
ID: 34172756
click on "Request Attention" and explain that to the moderator.
0
 

Author Comment

by:errang
ID: 34172816
ok, done.
0
 

Author Closing Comment

by:errang
ID: 34174025
Thanks
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Computer science students often experience many of the same frustrations when going through their engineering courses. This article presents seven tips I found useful when completing a bachelors and masters degree in computing which I believe may he…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question