Port of Artekit space invaders demo (http://www.artekit.eu/space-invaders-for-stm32/) for the STM32F3 Discovery board. Also shows game of life if started with the user button pressed.
Dependencies: STM32F3-Discovery
conway.c@2:1c1f7677ac17, 2016-05-17 (annotated)
- Committer:
- MartinJohnson
- Date:
- Tue May 17 23:53:10 2016 +0000
- Revision:
- 2:1c1f7677ac17
- Parent:
- 1:1b37c4b989b4
Remove old logo
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MartinJohnson | 1:1b37c4b989b4 | 1 | #include "stm32f30x.h" |
MartinJohnson | 1:1b37c4b989b4 | 2 | #include "video.h" |
MartinJohnson | 1:1b37c4b989b4 | 3 | |
MartinJohnson | 1:1b37c4b989b4 | 4 | typedef unsigned Unit; |
MartinJohnson | 1:1b37c4b989b4 | 5 | |
MartinJohnson | 1:1b37c4b989b4 | 6 | #define cols 416 |
MartinJohnson | 1:1b37c4b989b4 | 7 | #define rows 300 |
MartinJohnson | 1:1b37c4b989b4 | 8 | #define bits 32 |
MartinJohnson | 1:1b37c4b989b4 | 9 | |
MartinJohnson | 1:1b37c4b989b4 | 10 | extern char *fb[VID_VSIZE*2]; |
MartinJohnson | 1:1b37c4b989b4 | 11 | |
MartinJohnson | 1:1b37c4b989b4 | 12 | typedef struct { |
MartinJohnson | 1:1b37c4b989b4 | 13 | Unit sum; |
MartinJohnson | 1:1b37c4b989b4 | 14 | Unit carry; |
MartinJohnson | 1:1b37c4b989b4 | 15 | } AddResult; |
MartinJohnson | 1:1b37c4b989b4 | 16 | |
MartinJohnson | 1:1b37c4b989b4 | 17 | static void half_add(AddResult *c,Unit a, Unit b) { |
MartinJohnson | 1:1b37c4b989b4 | 18 | c->sum=a^b; |
MartinJohnson | 1:1b37c4b989b4 | 19 | c->carry=a&b; |
MartinJohnson | 1:1b37c4b989b4 | 20 | } |
MartinJohnson | 1:1b37c4b989b4 | 21 | |
MartinJohnson | 1:1b37c4b989b4 | 22 | static void full_add(AddResult *d, Unit a, Unit b, Unit c) { |
MartinJohnson | 1:1b37c4b989b4 | 23 | AddResult r0,r1; |
MartinJohnson | 1:1b37c4b989b4 | 24 | half_add(&r0,a, b); |
MartinJohnson | 1:1b37c4b989b4 | 25 | half_add(&r1,r0.sum, c); |
MartinJohnson | 1:1b37c4b989b4 | 26 | d->sum=r1.sum; |
MartinJohnson | 1:1b37c4b989b4 | 27 | d->carry=r0.carry | r1.carry; |
MartinJohnson | 1:1b37c4b989b4 | 28 | } |
MartinJohnson | 1:1b37c4b989b4 | 29 | |
MartinJohnson | 1:1b37c4b989b4 | 30 | static Unit col_step(Unit above[3], |
MartinJohnson | 1:1b37c4b989b4 | 31 | Unit current[3], |
MartinJohnson | 1:1b37c4b989b4 | 32 | Unit below[3]) { |
MartinJohnson | 1:1b37c4b989b4 | 33 | AddResult a_inf,b_inf,c_inf,next0,next1a,next1b; |
MartinJohnson | 1:1b37c4b989b4 | 34 | /* |
MartinJohnson | 1:1b37c4b989b4 | 35 | * Compute row-wise influence sums. This produces 96 2-bit sums (represented |
MartinJohnson | 1:1b37c4b989b4 | 36 | * as three pairs of 32-vectors) giving the number of live cells in the 1D |
MartinJohnson | 1:1b37c4b989b4 | 37 | * Moore neighborhood around each position. |
MartinJohnson | 1:1b37c4b989b4 | 38 | */ |
MartinJohnson | 1:1b37c4b989b4 | 39 | full_add(&a_inf,(above[1] << 1) | (above[0] >> (bits - 1)), |
MartinJohnson | 1:1b37c4b989b4 | 40 | above[1], |
MartinJohnson | 1:1b37c4b989b4 | 41 | (above[1] >> 1) | (above[2] << (bits - 1))); |
MartinJohnson | 1:1b37c4b989b4 | 42 | half_add(&c_inf,(current[1] << 1) | (current[0] >> (bits - 1)), |
MartinJohnson | 1:1b37c4b989b4 | 43 | /* middle bits of current[1] don't count */ |
MartinJohnson | 1:1b37c4b989b4 | 44 | (current[1] >> 1) | (current[2] << (bits - 1))); |
MartinJohnson | 1:1b37c4b989b4 | 45 | full_add(&b_inf,(below[1] << 1) | (below[0] >> (bits - 1)), |
MartinJohnson | 1:1b37c4b989b4 | 46 | below[1], |
MartinJohnson | 1:1b37c4b989b4 | 47 | (below[1] >> 1) | (below[2] << (bits - 1))); |
MartinJohnson | 1:1b37c4b989b4 | 48 | |
MartinJohnson | 1:1b37c4b989b4 | 49 | /* |
MartinJohnson | 1:1b37c4b989b4 | 50 | * Sum the row-wise sums into a two-dimensional Moore neighborhood population |
MartinJohnson | 1:1b37c4b989b4 | 51 | * count. Such a count can overflow into four bits, but we don't care: Conway |
MartinJohnson | 1:1b37c4b989b4 | 52 | * has the same result for 8/9 and 0/1 (the cell is cleared in both cases). |
MartinJohnson | 1:1b37c4b989b4 | 53 | * |
MartinJohnson | 1:1b37c4b989b4 | 54 | * Thus, we don't need a four-bit addition. Instead, we just retain the |
MartinJohnson | 1:1b37c4b989b4 | 55 | * carry output from the two intermediate additions and use it as a mask. |
MartinJohnson | 1:1b37c4b989b4 | 56 | */ |
MartinJohnson | 1:1b37c4b989b4 | 57 | full_add(&next0,a_inf.sum, c_inf.sum, b_inf.sum); |
MartinJohnson | 1:1b37c4b989b4 | 58 | full_add(&next1a,a_inf.carry, next0.carry, b_inf.carry); |
MartinJohnson | 1:1b37c4b989b4 | 59 | half_add(&next1b,c_inf.carry, next1a.sum); |
MartinJohnson | 1:1b37c4b989b4 | 60 | |
MartinJohnson | 1:1b37c4b989b4 | 61 | /* |
MartinJohnson | 1:1b37c4b989b4 | 62 | * Apply Niemiec's optimization: OR the current cell state vector into the |
MartinJohnson | 1:1b37c4b989b4 | 63 | * 9-cell neighborhoold population count to derive the new state cheaply. The |
MartinJohnson | 1:1b37c4b989b4 | 64 | * cell is set iff its three-bit sum is 0b011. |
MartinJohnson | 1:1b37c4b989b4 | 65 | */ |
MartinJohnson | 1:1b37c4b989b4 | 66 | return (next0.sum | current[1]) |
MartinJohnson | 1:1b37c4b989b4 | 67 | & next1b.sum |
MartinJohnson | 1:1b37c4b989b4 | 68 | & ~next1a.carry |
MartinJohnson | 1:1b37c4b989b4 | 69 | & ~next1b.carry; |
MartinJohnson | 1:1b37c4b989b4 | 70 | } |
MartinJohnson | 1:1b37c4b989b4 | 71 | |
MartinJohnson | 1:1b37c4b989b4 | 72 | |
MartinJohnson | 1:1b37c4b989b4 | 73 | |
MartinJohnson | 1:1b37c4b989b4 | 74 | static void step(Unit const *current_map, |
MartinJohnson | 1:1b37c4b989b4 | 75 | Unit *next_map, |
MartinJohnson | 1:1b37c4b989b4 | 76 | Unit width, |
MartinJohnson | 1:1b37c4b989b4 | 77 | Unit height) { |
MartinJohnson | 1:1b37c4b989b4 | 78 | // We keep sliding windows of state in these arrays. |
MartinJohnson | 1:1b37c4b989b4 | 79 | Unit above[3]={ 0, 0, 0 }; |
MartinJohnson | 1:1b37c4b989b4 | 80 | Unit current[3]={ 0, 0, 0 }; |
MartinJohnson | 1:1b37c4b989b4 | 81 | Unit below[3]={ 0, 0, 0 }; |
MartinJohnson | 1:1b37c4b989b4 | 82 | unsigned x,y; |
MartinJohnson | 1:1b37c4b989b4 | 83 | |
MartinJohnson | 1:1b37c4b989b4 | 84 | // Bootstrap for first column of first row. |
MartinJohnson | 1:1b37c4b989b4 | 85 | current[0] = current[1] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 86 | current[2] = current_map[0]; |
MartinJohnson | 0:404dae88af71 | 87 | |
MartinJohnson | 1:1b37c4b989b4 | 88 | below[0] = below[1] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 89 | below[2] = current_map[width]; |
MartinJohnson | 1:1b37c4b989b4 | 90 | |
MartinJohnson | 1:1b37c4b989b4 | 91 | #define ADV(name, next) \ |
MartinJohnson | 1:1b37c4b989b4 | 92 | name[0] = name[1]; \ |
MartinJohnson | 1:1b37c4b989b4 | 93 | name[1] = name[2]; \ |
MartinJohnson | 1:1b37c4b989b4 | 94 | name[2] = (next) |
MartinJohnson | 1:1b37c4b989b4 | 95 | |
MartinJohnson | 1:1b37c4b989b4 | 96 | // First row, wherein above[x] = 0, less final column |
MartinJohnson | 1:1b37c4b989b4 | 97 | for (x = 0; x < width - 1; ++x) { |
MartinJohnson | 1:1b37c4b989b4 | 98 | ADV(current, current_map[x + 1]); |
MartinJohnson | 1:1b37c4b989b4 | 99 | ADV(below, current_map[width + x + 1]); |
MartinJohnson | 1:1b37c4b989b4 | 100 | next_map[x] = col_step(above, current, below); |
MartinJohnson | 1:1b37c4b989b4 | 101 | } |
MartinJohnson | 1:1b37c4b989b4 | 102 | |
MartinJohnson | 1:1b37c4b989b4 | 103 | |
MartinJohnson | 1:1b37c4b989b4 | 104 | // Final column of first row, wherein we cannot fetch next values. |
MartinJohnson | 1:1b37c4b989b4 | 105 | ADV(current, 0); |
MartinJohnson | 1:1b37c4b989b4 | 106 | ADV(below, 0); |
MartinJohnson | 1:1b37c4b989b4 | 107 | next_map[width - 1] = col_step(above, current, below); |
MartinJohnson | 1:1b37c4b989b4 | 108 | |
MartinJohnson | 1:1b37c4b989b4 | 109 | // Remaining rows except the last. |
MartinJohnson | 1:1b37c4b989b4 | 110 | for (y = 1; y < height - 1; ++y) { |
MartinJohnson | 1:1b37c4b989b4 | 111 | unsigned offset = y * width; |
MartinJohnson | 1:1b37c4b989b4 | 112 | |
MartinJohnson | 1:1b37c4b989b4 | 113 | // Bootstrap row like we did for row 1. |
MartinJohnson | 1:1b37c4b989b4 | 114 | above[0] = above[1] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 115 | current[0] = current[1] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 116 | below[0] = below[1] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 117 | |
MartinJohnson | 1:1b37c4b989b4 | 118 | above[2] = current_map[offset - width]; |
MartinJohnson | 1:1b37c4b989b4 | 119 | current[2] = current_map[offset]; |
MartinJohnson | 1:1b37c4b989b4 | 120 | below[2] = current_map[offset + width]; |
MartinJohnson | 1:1b37c4b989b4 | 121 | |
MartinJohnson | 1:1b37c4b989b4 | 122 | for (x = 0; x < width - 1; ++x) { |
MartinJohnson | 1:1b37c4b989b4 | 123 | ADV(above, current_map[offset - width + x + 1]); |
MartinJohnson | 1:1b37c4b989b4 | 124 | ADV(current, current_map[offset + x + 1]); |
MartinJohnson | 1:1b37c4b989b4 | 125 | ADV(below, current_map[offset + width + x + 1]); |
MartinJohnson | 1:1b37c4b989b4 | 126 | next_map[offset + x] = col_step(above, current, below); |
MartinJohnson | 1:1b37c4b989b4 | 127 | } |
MartinJohnson | 1:1b37c4b989b4 | 128 | |
MartinJohnson | 1:1b37c4b989b4 | 129 | // Last column. |
MartinJohnson | 1:1b37c4b989b4 | 130 | ADV(above, 0); |
MartinJohnson | 1:1b37c4b989b4 | 131 | ADV(current, 0); |
MartinJohnson | 1:1b37c4b989b4 | 132 | ADV(below, 0); |
MartinJohnson | 1:1b37c4b989b4 | 133 | next_map[offset + width - 1] = col_step(above, current, below); |
MartinJohnson | 1:1b37c4b989b4 | 134 | } |
MartinJohnson | 1:1b37c4b989b4 | 135 | |
MartinJohnson | 1:1b37c4b989b4 | 136 | // Final row, wherein below[x] = 0. |
MartinJohnson | 1:1b37c4b989b4 | 137 | unsigned offset = width * (height - 1); |
MartinJohnson | 1:1b37c4b989b4 | 138 | above[0] = above[1] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 139 | current[0] = current[1] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 140 | below[0] = below[1] = below[2] = 0; |
MartinJohnson | 1:1b37c4b989b4 | 141 | |
MartinJohnson | 1:1b37c4b989b4 | 142 | above[2] = current_map[offset - width]; |
MartinJohnson | 1:1b37c4b989b4 | 143 | current[2] = current_map[offset]; |
MartinJohnson | 1:1b37c4b989b4 | 144 | |
MartinJohnson | 1:1b37c4b989b4 | 145 | for (x = 0; x < width - 1; ++x) { |
MartinJohnson | 1:1b37c4b989b4 | 146 | ADV(above, current_map[offset - width + x + 1]); |
MartinJohnson | 1:1b37c4b989b4 | 147 | ADV(current, current_map[offset + x + 1]); |
MartinJohnson | 1:1b37c4b989b4 | 148 | next_map[offset + x] = col_step(above, current, below); |
MartinJohnson | 1:1b37c4b989b4 | 149 | } |
MartinJohnson | 1:1b37c4b989b4 | 150 | |
MartinJohnson | 1:1b37c4b989b4 | 151 | // Final column |
MartinJohnson | 1:1b37c4b989b4 | 152 | ADV(above, 0); |
MartinJohnson | 1:1b37c4b989b4 | 153 | ADV(current, 0); |
MartinJohnson | 1:1b37c4b989b4 | 154 | next_map[offset + width - 1] = col_step(above, current, below); |
MartinJohnson | 1:1b37c4b989b4 | 155 | |
MartinJohnson | 1:1b37c4b989b4 | 156 | #undef ADV |
MartinJohnson | 1:1b37c4b989b4 | 157 | } |
MartinJohnson | 1:1b37c4b989b4 | 158 | |
MartinJohnson | 1:1b37c4b989b4 | 159 | extern unsigned fboffset; |
MartinJohnson | 1:1b37c4b989b4 | 160 | |
MartinJohnson | 1:1b37c4b989b4 | 161 | void conway_demo() { |
MartinJohnson | 1:1b37c4b989b4 | 162 | Unit *current=(Unit *)fb[0]; |
MartinJohnson | 1:1b37c4b989b4 | 163 | Unit *next=(Unit *)fb[rows]; |
MartinJohnson | 1:1b37c4b989b4 | 164 | SPI1->CR1 |= SPI_FirstBit_LSB; |
MartinJohnson | 1:1b37c4b989b4 | 165 | |
MartinJohnson | 1:1b37c4b989b4 | 166 | while(1) { |
MartinJohnson | 1:1b37c4b989b4 | 167 | step(current,next,cols/bits,rows); |
MartinJohnson | 1:1b37c4b989b4 | 168 | fboffset=300*52; |
MartinJohnson | 1:1b37c4b989b4 | 169 | sysDelayMs(1); |
MartinJohnson | 1:1b37c4b989b4 | 170 | step(next,current,cols/bits,rows); |
MartinJohnson | 1:1b37c4b989b4 | 171 | fboffset=0; |
MartinJohnson | 1:1b37c4b989b4 | 172 | sysDelayMs(1); |
MartinJohnson | 1:1b37c4b989b4 | 173 | } |
MartinJohnson | 1:1b37c4b989b4 | 174 | } |
MartinJohnson | 1:1b37c4b989b4 | 175 |