💾 Archived View for compudanzas.net › bouncing_ball_logic.gmi captured on 2024-05-10 at 10:56:35. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2024-03-21)
-=-=-=-=-=-=-
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.
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
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)
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.
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