211 lines
4.2 KiB
Plaintext
211 lines
4.2 KiB
Plaintext
# bouncing ball logic
|
|
lang=en
|
|
may this serve as a reference for non-electronic, human-scale, very-slow implementations of digital circuits that embody a virtual ball bouncing in a screen.
|
|
|
|
these notes emerged from the work around {poñg}, "a human-scale digital videogame, with logic provided by people".
|
|
|
|
this is a sub-collection from the {logiteca}.
|
|
|
|
# 1-dimension
|
|
|
|
## 4-pixels wide screen
|
|
|
|
the ball is a pixel that bounces back and forth.
|
|
|
|
description of the logic in {verilog}:
|
|
|
|
```
|
|
// bouncing ball (pixel) in a 4-pixels screen
|
|
// using NOR gates
|
|
module onedimensional_bounce( E2, E1, E0, P3, P2, P1, P0, NE2, NE1, NE0 );
|
|
|
|
input wire E2, E1, E0; // curent state
|
|
output wire P3, P2, P1, P0; // pixels
|
|
output wire NE2, NE1, NE0; // next state
|
|
|
|
// inversions
|
|
wire nE2, nE1, nE0;
|
|
|
|
// ors
|
|
wire NE0_1, NE0_2, NE1_2;
|
|
|
|
// input inversions (3 gates)
|
|
not g00( nE0, E0);
|
|
not g01( nE1, E1);
|
|
not g02( nE2, E2);
|
|
|
|
// NE2
|
|
assign NE2 = E1;
|
|
|
|
// NE1
|
|
nor g03( NE1_2, nE2, nE0);
|
|
nor g04( NE1, P0, NE1_2);
|
|
|
|
// NE0
|
|
nor g05( NE0_1, nE2, E1, nE0);
|
|
nor g06( NE0_2, E2, nE1, nE0);
|
|
nor g07( NE0, NE0_1, NE0_2);
|
|
|
|
// pixels
|
|
nor g08( P3, nE1, E0);
|
|
nor g09( P2, nE1, nE0);
|
|
nor g10( P1, E1, nE0);
|
|
nor g11( P0, E1, E0); // also "NE1_1"
|
|
|
|
endmodule
|
|
```
|
|
|
|
### board and cards implementation
|
|
|
|
compatible with {beans computing}: use two classes of beans to indicate a 1 or a 0.
|
|
|
|
current state:
|
|
```
|
|
+----+----+----+
|
|
| i2 | i1 | i0 |
|
|
+----+----+----+
|
|
```
|
|
|
|
process helpers
|
|
```
|
|
+----+----+----+----+----+----+
|
|
| p5 | p4 | p3 | p2 | p1 | p0 |
|
|
+----+----+----+----+----+----+
|
|
```
|
|
|
|
next state and screen:
|
|
```
|
|
+----+----+----+ +----+----+----+----+
|
|
| o6 | o5 | o4 | | o3 | o2 | o1 | o0 |
|
|
+----+----+----+ +----+----+----+----+
|
|
```
|
|
|
|
|
|
the NOR-based cards for process and output cells:
|
|
|
|
process helpers:
|
|
```
|
|
p0: i0
|
|
p1: i1
|
|
p2: i2
|
|
p3: p2, p0
|
|
p4: p2, i1, p0
|
|
p5: i2, p1, p0
|
|
```
|
|
|
|
next state:
|
|
```
|
|
o6: p1
|
|
o5: o0, p3
|
|
o4: p4, p5
|
|
```
|
|
|
|
screen:
|
|
```
|
|
o3: p1, i0
|
|
o2: p1, p0
|
|
o1: i1, p0
|
|
o0: i1, i0
|
|
```
|
|
|
|
(card p0 would be read: p0 is 1 when i0 is 0, and it's 0 otherwise; card p5 would be read: p5 is 1 when all i2, p1 and p0 are 0, and it's 0 otherwise)
|
|
|
|
|
|
# 2-dimensions
|
|
|
|
## 8x6 screen
|
|
|
|
the following description, converted into a gate-level representation, results in the {bouncer-2d prototype}. the notes of how that process happened have to be recovered and documented here.
|
|
|
|
### high-level verilog code
|
|
```
|
|
module bouncer2d
|
|
#(
|
|
parameter PIXELSW = 8,
|
|
parameter PIXELSH = 6
|
|
)
|
|
(
|
|
input [$clog2(PIXELSW)-1:0] posx,
|
|
input [$clog2(PIXELSH)-1:0] posy,
|
|
input dirx,
|
|
input diry,
|
|
output [$clog2(PIXELSW)-1:0] newposx,
|
|
output [$clog2(PIXELSH)-1:0] newposy,
|
|
output newdirx,
|
|
output newdiry,
|
|
output [(PIXELSW*PIXELSH)-1:0] screen
|
|
);
|
|
|
|
|
|
bouncer1d #( .NPIXELS( PIXELSW)) bouncex (
|
|
.pos( posx ),
|
|
.dir( dirx ),
|
|
.newpos( newposx ),
|
|
.newdir( newdirx )
|
|
);
|
|
|
|
bouncer1d #( .NPIXELS( PIXELSH)) bouncey (
|
|
.pos( posy ),
|
|
.dir( diry ),
|
|
.newpos( newposy ),
|
|
.newdir( newdiry )
|
|
);
|
|
|
|
screen_decoder #(.PIXELSW(PIXELSW), .PIXELSH( PIXELSH ))
|
|
decoder (
|
|
.posx( posx ),
|
|
.posy( posy ),
|
|
.screen( screen )
|
|
);
|
|
|
|
endmodule // bouncer2d
|
|
|
|
|
|
module screen_decoder
|
|
#(
|
|
parameter PIXELSW = 8,
|
|
parameter PIXELSH = 6
|
|
)
|
|
(
|
|
input [$clog2(PIXELSW)-1:0] posx,
|
|
input [$clog2(PIXELSH)-1:0] posy,
|
|
output [(PIXELSW*PIXELSH)-1:0] screen
|
|
);
|
|
|
|
// decoder!
|
|
genvar c, r;
|
|
generate
|
|
for(c=0; c<PIXELSW; c = c + 1) begin
|
|
for(r=0; r<PIXELSH; r = r + 1) begin
|
|
assign screen[c + r*PIXELSW] = (posx==c) && (posy==r);
|
|
end
|
|
end
|
|
endgenerate
|
|
|
|
// another possibility, less effective while synthesizing
|
|
// assign screen = (1<<posx) << (posy*PIXELSW);
|
|
|
|
endmodule // screen_decoder
|
|
|
|
|
|
module bouncer1d
|
|
#( parameter NPIXELS = 8)
|
|
(
|
|
input [$clog2(NPIXELS)-1:0] pos,
|
|
input dir, // 1 inc, 0 dec
|
|
output [$clog2(NPIXELS)-1:0] newpos,
|
|
output newdir
|
|
);
|
|
|
|
/* //without edge-cases
|
|
assign newdir = (dir==1 && pos==(NPIXELS-2)) ? 0 : (dir==0 && pos==1) ? 1 : dir;
|
|
assign newpos = (dir==1) ? pos + 1 : pos - 1;
|
|
*/
|
|
|
|
|
|
// with edge cases (and less gates when synthesizing!)
|
|
assign newdir = (pos==0) ? 1 : (pos>=NPIXELS-1) ? 0 : (dir==1 && pos==NPIXELS-2) || (dir==0 && pos==1) ? ~dir : dir;
|
|
assign newpos = (pos==0) ? 1 : (pos>=NPIXELS-1) ? NPIXELS - 2 : (dir==1)? pos + 1 : pos -1;
|
|
|
|
endmodule
|
|
``` |