Solved

A question about programming FPGA's in C

Posted on 2010-11-16
16
1,040 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
 

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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Suggested Solutions

This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
This article will show, step by step, how to integrate R code into a R Sweave document
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

744 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now