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 8

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
// # Copyright (c) 2020, Stephan Nolting. All rights reserved.                                     #
7
// #                                                                                               #
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
 * @file blink_led/main.c
38
 * @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
/**@}*/
58
 
59
 
60
 
61
/**********************************************************************//**
62
 * The universe
63
 **************************************************************************/
64
uint8_t universe[2][NUM_CELLS_X/8][NUM_CELLS_Y];
65
 
66
// Prototypes
67
void clear_universe(int u);
68
void set_cell(int u, int x, int y);
69
int get_cell(int u, int x, int y);
70
int get_neighborhood(int u, int x, int y);
71
void print_universe(int u);
72
int pop_count(int u);
73
uint32_t xorshift32(void);
74
 
75
 
76
/**********************************************************************//**
77
 * Conway's Game of Life.
78
 *
79
 * @note This program requires the UART to be synthesized (the TRNG is optional).
80
 *
81
 * @return Irrelevant.
82
 **************************************************************************/
83
int main(void) {
84
 
85
  // check if UART unit is implemented at all
86
  if (neorv32_uart_available() == 0) {
87
    return 0;
88
  }
89
 
90
 
91
  // capture all exceptions and give debug info via UART
92
  // this is not required, but keeps us safe
93
  neorv32_rte_enable_debug_mode();
94
 
95
 
96
  // init UART at default baud rate, no rx interrupt, no tx interrupt
97
  neorv32_uart_setup(BAUD_RATE, 0, 0);
98
 
99
 
100
  while (1) {
101
 
102
    int u = 0, cell = 0, n = 0;
103
    int x, y;
104
    int trng_available = 0;
105
    uint16_t trng_data;
106
 
107
 
108
    // initialize universe
109
    uint32_t generation = 0;
110
    clear_universe(0);
111
    clear_universe(1);
112
 
113
    // intro
114
    neorv32_uart_printf("\n\n<<< Conways's Game of Life >>>\n\n");
115
    neorv32_uart_printf("This program requires a terminal resolution of at least %ux%u characters.\n", NUM_CELLS_X+2, NUM_CELLS_Y+3);
116
    neorv32_uart_printf("Press any key to start a random-initialized torus-style universe of %ux%u cells.\n", NUM_CELLS_X, NUM_CELLS_Y);
117
    neorv32_uart_printf("You can pause/restart the simulation by pressing any key.\n");
118
 
119
 
120
    // check if TRNG was synthesized
121
    if (neorv32_trng_available()) {
122
      uint16_t trng_tap_config = neorv32_trng_find_tap_mask();
123
      neorv32_trng_setup(trng_tap_config);
124
      neorv32_uart_printf("\nTRNG detected (tap mask 0x%x). Using TRNG for universe initialization.\n", (uint32_t)trng_tap_config);
125
      trng_available = 1;
126
    }
127
 
128
 
129
    // randomize until key pressed
130
    while (neorv32_uart_char_received() == 0) {
131
      xorshift32();
132
    }
133
 
134
 
135
    // initialize universe using random data
136
    for (x=0; x<NUM_CELLS_X/8; x++) {
137
      for (y=0; y<NUM_CELLS_Y; y++) {
138
        if (trng_available) {
139
          if (neorv32_trng_get(&trng_data)) {
140
            neorv32_uart_printf("TRNG error!\n");
141
            return 1;
142
          }
143
          universe[0][x][y] = (uint8_t)trng_data; // use data from TRNG
144
        }
145
        else {
146
          universe[0][x][y] = (uint8_t)xorshift32(); // use data from PRNG
147
        }
148
      }
149
    }
150
 
151
 
152
    while(1) {
153
 
154
      // user abort?
155
      if (neorv32_uart_char_received()) {
156
        neorv32_uart_printf("\nRestart (y/n)?");
157
        if (neorv32_uart_getc() == 'y') {
158
          break;
159
        }
160
      }
161
 
162
      // print generation, population count and the current universe
163
      neorv32_uart_printf("\n\nGeneration %u: %u/%u living cells\n", (uint32_t)generation, (uint32_t)pop_count(u), NUM_CELLS_X*NUM_CELLS_Y);
164
      print_universe(u);
165
 
166
      // compute next generation
167
      clear_universe((u + 1) & 1);
168
 
169
      for (x=0; x<NUM_CELLS_X; x++) {
170
        for (y=0; y<NUM_CELLS_Y; y++) {
171
 
172
          cell = get_cell(u, x, y); // state of current cell
173
          n = get_neighborhood(u, x, y); // number of living neighbor cells
174
 
175
          // classic rule set
176
          if (((cell == 0) && (n == 3)) || ((cell != 0) && ((n == 2) || (n == 3)))) {
177
            set_cell((u + 1) & 1, x, y);
178
          }
179
 
180
        } // y
181
      } // x
182
      u = (u + 1) & 1; // switch universe
183
      generation++;
184
 
185
      // wait GEN_DELAY ms
186
      neorv32_cpu_delay_ms(GEN_DELAY);
187
    }
188
 
189
  }
190
 
191
  return 0;
192
}
193
 
194
 
195
/**********************************************************************//**
196
 * Print universe via UARt.
197
 *
198
 * @param[in] u Universe select (0 or 1).
199
 **************************************************************************/
200
void print_universe(int u){
201
 
202
  int16_t x, y;
203
 
204
  neorv32_uart_putc('+');
205
  for (x=0; x<NUM_CELLS_X; x++) {
206
    neorv32_uart_putc('-');
207
  }
208
  neorv32_uart_putc('+');
209
  neorv32_uart_putc('\r');
210
  neorv32_uart_putc('\n');
211
 
212
  for (y=0; y<NUM_CELLS_Y; y++) {
213
    neorv32_uart_putc('|');
214
 
215
    for (x=0; x<NUM_CELLS_X; x++) {
216
      if (get_cell(u, x, y))
217
        neorv32_uart_putc('#');
218
      else
219
        neorv32_uart_putc(' ');
220
    }
221
 
222
    // end of line
223
    neorv32_uart_putc('|');
224
    neorv32_uart_putc('\r');
225
    neorv32_uart_putc('\n');
226
  }
227
 
228
  neorv32_uart_putc('+');
229
  for (x=0; x<NUM_CELLS_X; x++) {
230
    neorv32_uart_putc('-');
231
  }
232
  neorv32_uart_putc('+');
233
}
234
 
235
 
236
/**********************************************************************//**
237
 * Kill all cells in universe.
238
 *
239
 * @param[in] u Universe select (0 or 1).
240
 **************************************************************************/
241
void clear_universe(int u){
242
 
243
  uint16_t x, y;
244
 
245
  for (x=0; x<NUM_CELLS_X/8; x++) {
246
    for (y=0; y<NUM_CELLS_Y; y++) {
247
      universe[u][x][y] = 0;
248
    }
249
  }
250
}
251
 
252
 
253
/**********************************************************************//**
254
 * Make cell alive.
255
 *
256
 * @param[in] u Universe select (0 or 1).
257
 * @param[in] x X coordinate of cell.
258
 * @param[in] y Y coordinate of cell.
259
 **************************************************************************/
260
void set_cell(int u, int x, int y){
261
 
262
  if ((x >= NUM_CELLS_X) || (y >= NUM_CELLS_Y))
263
    return; // out of range
264
 
265
  universe[u][x>>3][y] |= (uint8_t)(1 << (7 - (x & 7)));
266
}
267
 
268
 
269
/**********************************************************************//**
270
 * Get state of cell.
271
 *
272
 * @param[in] u Universe select (0 or 1).
273
 * @param[in] x X coordinate of cell.
274
 * @param[in] y Y coordinate of cell.
275
 * @return Cell is dead when 0, cell is alive when 1.
276
 **************************************************************************/
277
int get_cell(int u, int x, int y){
278
 
279
  // range check: wrap around -> torus-style universe
280
  if (x < 0)
281
    x = NUM_CELLS_X-1;
282
 
283
  if (x > NUM_CELLS_X-1)
284
    x = 0;
285
 
286
  if (y < 0)
287
    y = NUM_CELLS_Y-1;
288
 
289
  if (y > NUM_CELLS_Y-1)
290
    y = 0;
291
 
292
  // check bit according to cell
293
  uint8_t tmp = universe[u][x>>3][y];
294
  tmp &= 1 << (7 - (x & 7));
295
 
296
  if (tmp == 0)
297
    return 0; // DEAD
298
  else
299
    return 1; // ALIVE
300
}
301
 
302
 
303
/**********************************************************************//**
304
 * Get number of living cells in neighborhood.
305
 *
306
 * @param[in] u Universe select (0 or 1).
307
 * @param[in] x X coordinate of the neighborhood's center cell.
308
 * @param[in] y Y coordinate of the neighborhood's center cell.
309
 * @return Number of living cells in neighborhood (0..9).
310
 **************************************************************************/
311
int get_neighborhood(int u, int x, int y){
312
 
313
// Cell index layout:
314
// 012
315
// 3#4
316
// 567
317
 
318
  int num = 0;
319
  num += get_cell(u, x-1, y-1); // 0
320
  num += get_cell(u, x,   y-1); // 1
321
  num += get_cell(u, x+1, y-1); // 2
322
  num += get_cell(u, x-1, y);   // 3
323
  num += get_cell(u, x+1, y);   // 4
324
  num += get_cell(u, x-1, y+1); // 5
325
  num += get_cell(u, x,   y+1); // 6
326
  num += get_cell(u, x+1, y+1); // 7
327
 
328
  return num;
329
}
330
 
331
 
332
/**********************************************************************//**
333
 * Count living cells in universe.
334
 *
335
 * @param[in] u Universe select (0 or 1).
336
 * @return Number of living cells.
337
 **************************************************************************/
338
int pop_count(int u) {
339
 
340
  int x, y, cnt;
341
 
342
  cnt = 0;
343
  for (x=0; x<NUM_CELLS_X; x++) {
344
    for (y=0; y<NUM_CELLS_Y; y++) {
345
      cnt += (int)get_cell(u, x, y);
346
    }
347
  }
348
 
349
  return cnt;
350
}
351
 
352
 
353
/**********************************************************************//**
354
 * Simple pseudo random number generator.
355
 *
356
 * @return Random number.
357
 **************************************************************************/
358
uint32_t xorshift32(void) {
359
 
360
  static uint32_t x32 = 314159265;
361
 
362
  x32 ^= x32 << 13;
363
  x32 ^= x32 >> 17;
364
  x32 ^= x32 << 5;
365
 
366
  return x32;
367
}

powered by: WebSVN 2.1.0

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