OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [example/] [game_of_life/] [main.c] - Blame information for rev 65

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 zero_gravi
// #################################################################################################
2
// # << NEORV32 - Conway's Game of Life >>                                                         #
3
// # ********************************************************************************************* #
4
// # BSD 3-Clause License                                                                          #
5
// #                                                                                               #
6 44 zero_gravi
// # Copyright (c) 2021, Stephan Nolting. All rights reserved.                                     #
7 2 zero_gravi
// #                                                                                               #
8
// # Redistribution and use in source and binary forms, with or without modification, are          #
9
// # permitted provided that the following conditions are met:                                     #
10
// #                                                                                               #
11
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
12
// #    conditions and the following disclaimer.                                                   #
13
// #                                                                                               #
14
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
15
// #    conditions and the following disclaimer in the documentation and/or other materials        #
16
// #    provided with the distribution.                                                            #
17
// #                                                                                               #
18
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
19
// #    endorse or promote products derived from this software without specific prior written      #
20
// #    permission.                                                                                #
21
// #                                                                                               #
22
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
23
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
24
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
25
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
26
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
27
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
28
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
29
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
30
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
31
// # ********************************************************************************************* #
32
// # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
33
// #################################################################################################
34
 
35
 
36
/**********************************************************************//**
37 20 zero_gravi
 * @file game_of_life/main.c
38 2 zero_gravi
 * @author Stephan Nolting
39
 * @brief Simple blinking LED demo program using the lowest 8 bits of the GPIO.output port.
40
 **************************************************************************/
41
 
42
#include <neorv32.h>
43
 
44
 
45
/**********************************************************************//**
46
 * @name User configuration
47
 **************************************************************************/
48
/**@{*/
49
/** UART BAUD rate */
50
#define BAUD_RATE     19200
51
/** Universe x size (has to be a multiple of 8) */
52
#define NUM_CELLS_X   160
53
/** Universe y size */
54
#define NUM_CELLS_Y   40
55
/** Delay between generations in ms */
56
#define GEN_DELAY     500
57 22 zero_gravi
/** Symbol for dead cell */
58
#define CELL_DEAD  (' ')
59
/** Symbol for alive cell */
60
#define CELL_ALIVE ('#')
61 2 zero_gravi
/**@}*/
62
 
63
 
64
 
65
/**********************************************************************//**
66
 * The universe
67
 **************************************************************************/
68
uint8_t universe[2][NUM_CELLS_X/8][NUM_CELLS_Y];
69
 
70
// Prototypes
71
void clear_universe(int u);
72
void set_cell(int u, int x, int y);
73
int get_cell(int u, int x, int y);
74
int get_neighborhood(int u, int x, int y);
75
void print_universe(int u);
76
int pop_count(int u);
77
uint32_t xorshift32(void);
78
 
79
 
80
/**********************************************************************//**
81
 * Conway's Game of Life.
82
 *
83
 * @note This program requires the UART to be synthesized (the TRNG is optional).
84
 *
85 60 zero_gravi
 * @return 0 if execution was successful
86 2 zero_gravi
 **************************************************************************/
87
int main(void) {
88
 
89
  // check if UART unit is implemented at all
90 65 zero_gravi
  if (neorv32_uart0_available() == 0) {
91 60 zero_gravi
    return 1;
92 2 zero_gravi
  }
93
 
94
 
95
  // capture all exceptions and give debug info via UART
96
  // this is not required, but keeps us safe
97 14 zero_gravi
  neorv32_rte_setup();
98 2 zero_gravi
 
99
 
100 51 zero_gravi
  // init UART at default baud rate, no parity bits, ho hw flow control
101 65 zero_gravi
  neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE);
102 2 zero_gravi
 
103 44 zero_gravi
  // check available hardware extensions and compare with compiler flags
104
  neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
105 2 zero_gravi
 
106 44 zero_gravi
 
107 2 zero_gravi
  while (1) {
108
 
109
    int u = 0, cell = 0, n = 0;
110
    int x, y;
111
    int trng_available = 0;
112 23 zero_gravi
    uint8_t trng_data;
113 2 zero_gravi
 
114
 
115
    // initialize universe
116
    uint32_t generation = 0;
117
    clear_universe(0);
118
    clear_universe(1);
119
 
120
    // intro
121 65 zero_gravi
    neorv32_uart0_printf("\n\n<<< Conways's Game of Life >>>\n\n");
122
    neorv32_uart0_printf("This program requires a terminal resolution of at least %ux%u characters.\n", NUM_CELLS_X+2, NUM_CELLS_Y+3);
123
    neorv32_uart0_printf("Press any key to start a random-initialized torus-style universe of %ux%u cells.\n", NUM_CELLS_X, NUM_CELLS_Y);
124
    neorv32_uart0_printf("You can pause/restart the simulation by pressing any key.\n");
125 2 zero_gravi
 
126
 
127
    // check if TRNG was synthesized
128
    if (neorv32_trng_available()) {
129 65 zero_gravi
      neorv32_uart0_printf("\nTRNG detected. Using TRNG for universe initialization.\n");
130 23 zero_gravi
      neorv32_trng_enable();
131 2 zero_gravi
      trng_available = 1;
132
    }
133
 
134
 
135
    // randomize until key pressed
136 65 zero_gravi
    while (neorv32_uart0_char_received() == 0) {
137 2 zero_gravi
      xorshift32();
138
    }
139
 
140
 
141
    // initialize universe using random data
142
    for (x=0; x<NUM_CELLS_X/8; x++) {
143
      for (y=0; y<NUM_CELLS_Y; y++) {
144
        if (trng_available) {
145 23 zero_gravi
          while (1) {
146
            int err = neorv32_trng_get(&trng_data);
147
            if (err) {
148 65 zero_gravi
              neorv32_uart0_printf("TRNG error (%i)! Restarting TRNG...\n", err);
149 23 zero_gravi
              continue;
150
            }
151
            else {
152
              break;
153
            }
154 2 zero_gravi
          }
155 23 zero_gravi
          universe[0][x][y] = trng_data; // use data from TRNG
156 2 zero_gravi
        }
157
        else {
158
          universe[0][x][y] = (uint8_t)xorshift32(); // use data from PRNG
159
        }
160
      }
161
    }
162
 
163
 
164
    while(1) {
165
 
166
      // user abort?
167 65 zero_gravi
      if (neorv32_uart0_char_received()) {
168
        neorv32_uart0_printf("\nRestart (y/n)?");
169
        if (neorv32_uart0_getc() == 'y') {
170 2 zero_gravi
          break;
171
        }
172
      }
173
 
174
      // print generation, population count and the current universe
175 65 zero_gravi
      neorv32_uart0_printf("\n\nGeneration %u: %u/%u living cells\n", (uint32_t)generation, (uint32_t)pop_count(u), NUM_CELLS_X*NUM_CELLS_Y);
176 2 zero_gravi
      print_universe(u);
177
 
178
      // compute next generation
179
      clear_universe((u + 1) & 1);
180
 
181
      for (x=0; x<NUM_CELLS_X; x++) {
182
        for (y=0; y<NUM_CELLS_Y; y++) {
183
 
184
          cell = get_cell(u, x, y); // state of current cell
185
          n = get_neighborhood(u, x, y); // number of living neighbor cells
186
 
187 22 zero_gravi
          // -- classic rule set --
188
          // if center cell is dead -> cell comes to life when there are exactly 3 living cells around
189
          // if center cell is alive -> stay alive if there are 2 or three living cells around
190
          // else -> cell is/becomes dead
191 2 zero_gravi
          if (((cell == 0) && (n == 3)) || ((cell != 0) && ((n == 2) || (n == 3)))) {
192
            set_cell((u + 1) & 1, x, y);
193
          }
194
 
195
        } // y
196
      } // x
197
      u = (u + 1) & 1; // switch universe
198
      generation++;
199
 
200
      // wait GEN_DELAY ms
201
      neorv32_cpu_delay_ms(GEN_DELAY);
202
    }
203
 
204
  }
205
 
206
  return 0;
207
}
208
 
209
 
210
/**********************************************************************//**
211
 * Print universe via UARt.
212
 *
213
 * @param[in] u Universe select (0 or 1).
214
 **************************************************************************/
215
void print_universe(int u){
216
 
217
  int16_t x, y;
218
 
219 65 zero_gravi
  neorv32_uart0_putc('+');
220 2 zero_gravi
  for (x=0; x<NUM_CELLS_X; x++) {
221 65 zero_gravi
    neorv32_uart0_putc('-');
222 2 zero_gravi
  }
223 65 zero_gravi
  neorv32_uart0_putc('+');
224
  neorv32_uart0_putc('\r');
225
  neorv32_uart0_putc('\n');
226 2 zero_gravi
 
227
  for (y=0; y<NUM_CELLS_Y; y++) {
228 65 zero_gravi
    neorv32_uart0_putc('|');
229 2 zero_gravi
 
230
    for (x=0; x<NUM_CELLS_X; x++) {
231
      if (get_cell(u, x, y))
232 65 zero_gravi
        neorv32_uart0_putc((char)CELL_ALIVE);
233 2 zero_gravi
      else
234 65 zero_gravi
        neorv32_uart0_putc((char)CELL_DEAD);
235 2 zero_gravi
    }
236
 
237
    // end of line
238 65 zero_gravi
    neorv32_uart0_putc('|');
239
    neorv32_uart0_putc('\r');
240
    neorv32_uart0_putc('\n');
241 2 zero_gravi
  }
242
 
243 65 zero_gravi
  neorv32_uart0_putc('+');
244 2 zero_gravi
  for (x=0; x<NUM_CELLS_X; x++) {
245 65 zero_gravi
    neorv32_uart0_putc('-');
246 2 zero_gravi
  }
247 65 zero_gravi
  neorv32_uart0_putc('+');
248 2 zero_gravi
}
249
 
250
 
251
/**********************************************************************//**
252
 * Kill all cells in universe.
253
 *
254
 * @param[in] u Universe select (0 or 1).
255
 **************************************************************************/
256
void clear_universe(int u){
257
 
258
  uint16_t x, y;
259
 
260
  for (x=0; x<NUM_CELLS_X/8; x++) {
261
    for (y=0; y<NUM_CELLS_Y; y++) {
262
      universe[u][x][y] = 0;
263
    }
264
  }
265
}
266
 
267
 
268
/**********************************************************************//**
269
 * Make cell alive.
270
 *
271
 * @param[in] u Universe select (0 or 1).
272
 * @param[in] x X coordinate of cell.
273
 * @param[in] y Y coordinate of cell.
274
 **************************************************************************/
275
void set_cell(int u, int x, int y){
276
 
277
  if ((x >= NUM_CELLS_X) || (y >= NUM_CELLS_Y))
278
    return; // out of range
279
 
280
  universe[u][x>>3][y] |= (uint8_t)(1 << (7 - (x & 7)));
281
}
282
 
283
 
284
/**********************************************************************//**
285
 * Get state of cell.
286
 *
287
 * @param[in] u Universe select (0 or 1).
288
 * @param[in] x X coordinate of cell.
289
 * @param[in] y Y coordinate of cell.
290
 * @return Cell is dead when 0, cell is alive when 1.
291
 **************************************************************************/
292
int get_cell(int u, int x, int y){
293
 
294
  // range check: wrap around -> torus-style universe
295
  if (x < 0)
296
    x = NUM_CELLS_X-1;
297
 
298
  if (x > NUM_CELLS_X-1)
299
    x = 0;
300
 
301
  if (y < 0)
302
    y = NUM_CELLS_Y-1;
303
 
304
  if (y > NUM_CELLS_Y-1)
305
    y = 0;
306
 
307
  // check bit according to cell
308
  uint8_t tmp = universe[u][x>>3][y];
309
  tmp &= 1 << (7 - (x & 7));
310
 
311
  if (tmp == 0)
312
    return 0; // DEAD
313
  else
314
    return 1; // ALIVE
315
}
316
 
317
 
318
/**********************************************************************//**
319
 * Get number of living cells in neighborhood.
320
 *
321
 * @param[in] u Universe select (0 or 1).
322
 * @param[in] x X coordinate of the neighborhood's center cell.
323
 * @param[in] y Y coordinate of the neighborhood's center cell.
324
 * @return Number of living cells in neighborhood (0..9).
325
 **************************************************************************/
326
int get_neighborhood(int u, int x, int y){
327
 
328
// Cell index layout:
329
// 012
330
// 3#4
331
// 567
332
 
333
  int num = 0;
334
  num += get_cell(u, x-1, y-1); // 0
335
  num += get_cell(u, x,   y-1); // 1
336
  num += get_cell(u, x+1, y-1); // 2
337
  num += get_cell(u, x-1, y);   // 3
338
  num += get_cell(u, x+1, y);   // 4
339
  num += get_cell(u, x-1, y+1); // 5
340
  num += get_cell(u, x,   y+1); // 6
341
  num += get_cell(u, x+1, y+1); // 7
342
 
343
  return num;
344
}
345
 
346
 
347
/**********************************************************************//**
348
 * Count living cells in universe.
349
 *
350
 * @param[in] u Universe select (0 or 1).
351
 * @return Number of living cells.
352
 **************************************************************************/
353
int pop_count(int u) {
354
 
355
  int x, y, cnt;
356
 
357
  cnt = 0;
358
  for (x=0; x<NUM_CELLS_X; x++) {
359
    for (y=0; y<NUM_CELLS_Y; y++) {
360
      cnt += (int)get_cell(u, x, y);
361
    }
362
  }
363
 
364
  return cnt;
365
}
366
 
367
 
368
/**********************************************************************//**
369
 * Simple pseudo random number generator.
370
 *
371
 * @return Random number.
372
 **************************************************************************/
373
uint32_t xorshift32(void) {
374
 
375
  static uint32_t x32 = 314159265;
376
 
377
  x32 ^= x32 << 13;
378
  x32 ^= x32 >> 17;
379
  x32 ^= x32 << 5;
380
 
381
  return x32;
382
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.