////////////////////////////////////////////////////////////////////////////////// // File : main.c (for gameoflife) // Date : November 2013 // Author : Alexandre Joannou // // This application is an emulation of the game of life automaton. // The world size is defined by the HEIGHT and WIDTH parameters. // There is one task per processor, and each task compute HEIGHT/nbprocs lines. // The number of processors must be a power of 2 not larger than HEIGHT. ////////////////////////////////////////////////////////////////////////////////// #include "stdio.h" #include "limits.h" #include "user_barrier.h" #include "mapping_info.h" #define WIDTH 128 #define HEIGHT 128 #define NB_ITERATION 1000000000 #define PRINTF(...) ({ if ( proc_id==0) { giet_shr_printf(__VA_ARGS__); } }) giet_sqt_barrier_t barrier; volatile unsigned int init_ok; #define OLD 0 #define NEW 1 #define DSP 2 typedef unsigned char uint8_t; typedef unsigned int size_t; uint8_t world[3][HEIGHT][WIDTH]; ///////////////////////////////////////////////// void init_world(size_t base_line, size_t nb_line) { size_t x,y; for (y = base_line ; y < base_line + nb_line; y++) { for(x = 0; x < WIDTH ; x++) { world[OLD][y][x] = (giet_rand() >> (x % 8)) & 0x1; } } } ///////////////////////////////////////////////// uint8_t number_of_alive_neigh(size_t x, size_t y) { uint8_t nb = 0; nb += world[OLD][(y - 1) % HEIGHT][(x - 1) % WIDTH]; nb += world[OLD][ y ][(x - 1) % WIDTH]; nb += world[OLD][(y + 1) % HEIGHT][(x - 1) % WIDTH]; nb += world[OLD][(y - 1) % HEIGHT][ x ]; nb += world[OLD][(y + 1) % HEIGHT][ x ]; nb += world[OLD][(y - 1) % HEIGHT][(x + 1) % WIDTH]; nb += world[OLD][ y ][(x + 1) % WIDTH]; nb += world[OLD][(y + 1) % HEIGHT][(x + 1) % WIDTH]; return nb; } ///////////////////////////////////////////////// uint8_t compute_cell(size_t x, size_t y) { uint8_t nb_neighbours_alive = number_of_alive_neigh(x,y); if (world[OLD][y][x] == 1) { if (nb_neighbours_alive == 2 || nb_neighbours_alive == 3) return 1; } else { if (nb_neighbours_alive == 3) return 1; else return world[OLD][y][x]; } return 0; } ////////////////////////////////////////////////////// void compute_new_gen(size_t base_line, size_t nb_line) { size_t x,y; for (y = base_line; y < base_line + nb_line; y++) { for(x = 0; x < WIDTH ; x++) { world[NEW][y][x] = compute_cell(x,y); } } } //////////////////////////////////////////////////// void display_world(size_t base_line, size_t nb_line) { size_t x,y; for (y = base_line; y < base_line + nb_line; y++) { for(x = 0; x < WIDTH ; x++) { world[DSP][y][x] = world[OLD][y][x]*255; } } giet_fbf_sync_write( base_line * WIDTH , &world[DSP][base_line][0], nb_line * WIDTH ); } ///////////////////////////////////////////////////// void grow_old_world(size_t base_line, size_t nb_line) { size_t x,y; for (y = base_line; y < base_line + nb_line; y++) { for(x = 0; x < WIDTH ; x++) { world[OLD][y][x] = world[NEW][y][x]; } } } //////////////////////////////////////// __attribute__((constructor)) void main() { // get processor identifier unsigned int x; unsigned int y; unsigned int p; giet_proc_xyp( &x, &y, &p ); // get processors number unsigned int x_size; unsigned int y_size; unsigned int n_local_procs; giet_procs_number( &x_size, &y_size, &n_local_procs ); // compute continuous processor index unsigned int proc_id = (((x * y_size) + y) * n_local_procs) + p; unsigned int n_clusters = x_size * y_size; // number of clusters unsigned int n_global_procs = n_clusters * n_local_procs; // number of processors size_t i; if ( n_global_procs > HEIGHT ) { PRINTF("[GAMEOFLIFE ERROR] Number or processors too large :" " nb_procs = %d / image heigth = %d\n", n_global_procs, HEIGHT ); giet_exit("error"); } size_t nb_line = HEIGHT / n_global_procs; size_t base_line = nb_line * proc_id; PRINTF("\n*** Starting barrier initialisation at cycle %d ***\n" " nprocs = %d / nlines = %d\n", giet_proctime() , n_global_procs, HEIGHT ); // barrier initialization if ( proc_id == 0 ) { sqt_barrier_init( &barrier , x_size , y_size , n_local_procs ); init_ok = 1; } else { while ( init_ok == 0 ) asm volatile("nop\n nop\n nop"); } PRINTF("\n*** Starting world initialisation at cycle %d ***\n", giet_proctime() ); // parallel world initialization init_world( base_line , nb_line ); display_world( base_line , nb_line ); sqt_barrier_wait( &barrier ); PRINTF("\n*** Starting life at cycle %d ***\n", giet_proctime() ); for (i = 0; i < NB_ITERATION; i++) { compute_new_gen( base_line, nb_line ); grow_old_world( base_line, nb_line ); display_world( base_line, nb_line ); sqt_barrier_wait( &barrier ); PRINTF(" - iteration %d completed\n", i ); } PRINTF("\n*** End of main at cycle %d ***\n", giet_proctime()); giet_exit("Completed"); } // end main() // Local Variables: // tab-width: 3 // c-basic-offset: 3 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=cpp:expandtab:shiftwidth=3:tabstop=3:softtabstop=3