/* life1 The first simple version of Conway's Life on Mefisto 8x8 chess board. Copyright (C) 2005-2010, Antti Karttunen, His-firstname.His-surname@gmail.com This version from January 29 2010 adds the population & generation counts (the former is shown in two rightmost 7-seg led digits, while the leftmost 8 bits of the latter are shown as binary in the leds LD0--LD7.) Also as a novelty we have non-single-stepped operation. Switches 5-0 determine the running speed, from 1.514 Hz to 95.4 Hz. If they are all in 0-position, then we run in single-step mode. */ module life1(CLK,PB_IN,SW_IN,BCOL_IN,BCOL_OUT,BROW,LED_OUT,SEG_OUT,DIGIT_OUT); input CLK; input [3:0] PB_IN; input [7:0] SW_IN; input [7:0] BCOL_IN; output [7:0] BCOL_OUT; output [7:0] BROW; output [7:0] LED_OUT; output [7:0] SEG_OUT; output [3:0] DIGIT_OUT; // wire RST = PB_IN[3]; reg [7:0] BOARD_ROW [7:0]; wire [7:0] PIECES_ROW [7:0]; reg [6:0] popula = 7'b0000000; // Population count. From 0 to 64. reg [6:0] old_popula = 7'b1111111; // Its contents in the prev cycle. reg [15:0] this_generation = 0; wire [5:0] selected_speed = SW_IN[5:0]; // 2^19 * 20ns = 524288 * 20 ns = 0.0105 sec = 10.5 ms. (95.4 Hz) // 63 * 10.5 ms = 0.66 sec (1.51 Hz) reg [24:0] pause_counter = 24'b0000000000000000000000000; function fredkin; input n; input s; input w; input e; fredkin = (n^s^w^e); endfunction // The cell will be alife if it has either 3 neighbours // or if it has 2 neighbours and it itself is alive. function life; input c; input n; input ne; input s; input se; input w; input sw; input e; input nw; //life = (4'b0011 == ((n+ne+e+se+s+sw+w+nw)|c)); life = (4'b0011 == (({3'b000,n}+{3'b000,ne}+{3'b000,s}+{3'b000,se}+{3'b000,w}+{3'b000,sw}+{3'b000,e}+{3'b000,nw})|{3'b000,c})); endfunction function [3:0] c8b; input [7:0] b; c8b = ({3'b000,b[7]}+{3'b000,b[6]}+{3'b000,b[5]}+{3'b000,b[4]}+{3'b000,b[3]}+{3'b000,b[2]}+{3'b000,b[1]}+{3'b000,b[0]}); endfunction // Compute the pause period from the speed selection switches: function [24:0] get_pp; input [5:0] ss; // Speed switches 5:0. get_pp = ({~ss[0],~ss[1],~ss[2],~ss[3],~ss[4],~ss[5]}+6'b000001) << 19; endfunction mefi8x8a BOARD_IO(.CLK(CLK), .BCOL_IN(BCOL_IN), .BCOL_OUT(BCOL_OUT), .BROW(BROW), .LEDS2LIT0(BOARD_ROW[0]), .LEDS2LIT1(BOARD_ROW[1]), .LEDS2LIT2(BOARD_ROW[2]), .LEDS2LIT3(BOARD_ROW[3]), .LEDS2LIT4(BOARD_ROW[4]), .LEDS2LIT5(BOARD_ROW[5]), .LEDS2LIT6(BOARD_ROW[6]), .LEDS2LIT7(BOARD_ROW[7]), .PIECES0(PIECES_ROW[0]), .PIECES1(PIECES_ROW[1]), .PIECES2(PIECES_ROW[2]), .PIECES3(PIECES_ROW[3]), .PIECES4(PIECES_ROW[4]), .PIECES5(PIECES_ROW[5]), .PIECES6(PIECES_ROW[6]), .PIECES7(PIECES_ROW[7]) ); // wire [2:0] shrow = {SW_IN[2],SW_IN[1],SW_IN[0]}; wire input_mode = SW_IN[7]; wire PB_NEXT; // State of the debounced push button for incrementing. reg pb_next_prev = 0; // is saved here also. wire single_step_pressed = (PB_NEXT && ~pb_next_prev); // We proceed to compute the next generation when either // a) the user has selected non-zero pause-period (i.e. not single-step) // and the pause period has just completed (it's all zeros), // or // b) single_step button has been pressed: wire proceed = ((|selected_speed & ~|pause_counter) | single_step_pressed); reg [7:0] butbuf = 4'b0000; debounced_button DBB0(CLK,PB_IN[0],PB_NEXT); assign LED_OUT = this_generation[7:0]; wire show_pop_count = (butbuf[7]|(input_mode && (popula != old_popula))); // shw16decb DECDISPLAY(CLK,butbuf[7],this_generation[15:0],SEG_OUT,DIGIT_OUT); shw16decb DECDISPLAY(CLK,show_pop_count,{9'b000000000,popula[6:0]},SEG_OUT,DIGIT_OUT); integer i; // A "compile-time" index to board rows. (for the for loop). integer j; always @(posedge CLK) begin // if(RST) // begin // end // else begin pb_next_prev <= PB_NEXT; butbuf <= {butbuf[6:0],proceed}; // Shift butbuf one left, and get lsb from a debounced push-button. if(input_mode) begin // Transfer the state from input registers (reed relays) old_popula <= popula; // Sum the population total from the input state. popula <= {3'b000,c8b(PIECES_ROW[0])} + {3'b000,c8b(PIECES_ROW[1])} + {3'b000,c8b(PIECES_ROW[2])} + {3'b000,c8b(PIECES_ROW[3])} + {3'b000,c8b(PIECES_ROW[4])} + {3'b000,c8b(PIECES_ROW[5])} + {3'b000,c8b(PIECES_ROW[6])} + {3'b000,c8b(PIECES_ROW[7])}; this_generation <= 0; for(i=0; i<8; i=i+1) BOARD_ROW[i] <= PIECES_ROW[i]; pause_counter <= get_pp(selected_speed); end else if(proceed) // pause period has ended, or we are in single step mode begin // and the user has pressed the next button. pause_counter <= get_pp(selected_speed); old_popula <= popula; // Sum the population total from the current state. popula <= {3'b000,c8b(BOARD_ROW[0])} + {3'b000,c8b(BOARD_ROW[1])} + {3'b000,c8b(BOARD_ROW[2])} + {3'b000,c8b(BOARD_ROW[3])} + {3'b000,c8b(BOARD_ROW[4])} + {3'b000,c8b(BOARD_ROW[5])} + {3'b000,c8b(BOARD_ROW[6])} + {3'b000,c8b(BOARD_ROW[7])}; for(i=0; i<8; i=i+1) for(j=0; j<8; j=j+1) BOARD_ROW[i][j] <= life(BOARD_ROW[i][j], // The cell itself. BOARD_ROW[i][(7==j ? 0 : j+1)], // n BOARD_ROW[(7==i ? 0 : i+1)][(7==j ? 0 : j+1)], // ne BOARD_ROW[(7==i ? 0 : i+1)][j], // e BOARD_ROW[(7==i ? 0 : i+1)][(0==j ? 7 : j-1)], // se BOARD_ROW[i][(0==j ? 7 : j-1)], // s BOARD_ROW[(0==i ? 7 : i-1)][(0==j ? 7 : j-1)], // sw BOARD_ROW[(0==i ? 7 : i-1)][j], // w BOARD_ROW[(0==i ? 7 : i-1)][(7==j ? 0 : j+1)] // nw ); end else begin if(|selected_speed) pause_counter <= pause_counter - 1; if(butbuf[1]) this_generation <= this_generation + 1; end end end endmodule