compudanzas

bouncing ball logic

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

incoming links