← Back to projects

Nexys Rex

December 5, 2025

Nexys Rex

Summary

This project was done for my EGEC 446 class, Advanced Digital Design using Verilog HDL. Some features include a random seed using a linear feedback shift register, as well as multiple state machines to keep track of game and display logic.

System Interconnect/Design for Program
System Interconnect/Design for Program

Code

top_game_system.v

`timescale 1ns / 1ps
`include "constants.vh"

module top_game_system(
    input clk,
    input jump,
    input reset,
    output [6:0] sseg_out,
    output [7:0] an_out
    );
    
    wire sclk;
    // gets sent to LCD
    wire [23:0] display_game_state;
    
    wire [2:0] player_state;
    wire [23:0] shifted_state;

    // get value of slow clock to fit in other logic
    clock_divider clock_divider_module(.clk(clk), .reset(reset), .sclk(sclk));
    
    // grab value of player
    input_handler input_handler_module(
                .sclk(sclk),
                .reset(reset),
                .button(jump),
                .player_state(player_state)
                );
        
    // get value of shifted state
    game_shift game_shift_module(
                .sclk(sclk),
                .reset(reset),
                .shifted_game_state(shifted_state)
                );
    
    // pass value of display game state            
    collision collision_module(
                .sclk(sclk),
                .reset(reset),
                .shifted_display_state(shifted_state),
                .player_state(player_state),
                .combined_state(display_game_state)
                );

    // use display_game_state to update physical 7-segment
    seven_segment_top seven_segment_top_module(
        .clk(clk),
        .display_game_state(display_game_state), 
        .sseg_out(sseg_out), 
        .an_out(an_out));
    
endmodule

clock_divider.v

module clock_divider(
`include "constants.vh"

input clk,
input reset,
output reg sclk
);
    parameter CLOCK_DIVIDER_MAX_COUNT = 32'd49999999; // 1s period
    parameter CLOCK_DIVIDER_MIN_COUNT = 32'd12499999; // 250 ms period

    reg [31:0] speed_upper_bound;
    reg [31:0] count;
    always@(posedge clk or posedge reset) begin
        if (reset) begin
            count <= 32'd0;
            sclk <= 1'b0;
            speed_upper_bound <= CLOCK_DIVIDER_MAX_COUNT;
        end else begin
            if (count >= speed_upper_bound) begin // 100_000_000 per clock, divide by 
                count <= 32'd0;
                sclk <= ~sclk;
                speed_upper_bound <= (speed_upper_bound < CLOCK_DIVIDER_MIN_COUNT)? 
                    CLOCK_DIVIDER_MIN_COUNT : ((speed_upper_bound > CLOCK_DIVIDER_MAX_COUNT)? CLOCK_DIVIDER_MAX_COUNT : speed_upper_bound - 32'd450000);
            end else begin
                count <= count + 1;
            end
        end
    end
endmodule

input_handler.v

`timescale 1ns / 1ps
`include "constants.vh"

module input_handler(
    input wire sclk,
    input wire reset,
    input wire button,
    output wire [2:0] player_state
    );
    reg [2:0] curr;
    reg [2:0] next;
    
    // At each clock cycle assign the new state
    always @(posedge sclk or posedge reset) begin
        if (reset) begin
            curr <= `PLAYER_FLOOR_STATE;
        end else 
            curr <= next;
    end
    
    // Combinational part that selects next state based on input and current state
    always @(*) begin
        case(curr)
        
            `PLAYER_FLOOR_STATE: begin
                if (button) begin
                    next = `PLAYER_AIR_STATE;
                end else
                    next = `PLAYER_FLOOR_STATE;
             end
           
           `PLAYER_AIR_STATE: begin
                next = `PLAYER_FLOOR_STATE;
            end
                
           default: next = `PLAYER_FLOOR_STATE;
        endcase
    end
    
    assign player_state = curr;
        
endmodule

game_shift.v

`timescale 1ns / 1ps
`include "constants.vh"

module game_shift(
    input sclk,
    input reset,
    output reg [23:0] shifted_game_state
    );
        
    wire [2:0] LFSR_out;
    // MUST NOT SUPPLY TWO OBSTACLES CONSECUTIVELY
    wire [2:0] shift_in;
    
    LFSR_3 RNG(.CLK(sclk), .RST(reset), .LFSR_out(LFSR_out));
    // generate LFSR output into either an obstacle or a box
    assign shift_in = (((LFSR_out % 2) == 0) && (shifted_game_state[2:0] != `OBSTACLE_STATE)) 
                        ? `OBSTACLE_STATE : `FLOOR_STATE;
    
    
    // override player state with floor, shift everything left 
    always@(posedge sclk or posedge reset) begin
        if (reset)
            shifted_game_state <= `SHIFT_RESET_STATE;
        else
            shifted_game_state <= {shifted_game_state[20:0], shift_in};
    end
endmodule

LFSR_3.v

`timescale 1ns / 1ps
module LFSR_3 (
    input wire CLK,
    input wire RST,
    output wire [2:0] LFSR_out
);
    parameter [2:0] SEED = 3'b101;
    reg [2:0] LFSR;
    
    always @(posedge CLK or posedge RST) begin
        if (RST)
            LFSR <= SEED;
        else
            LFSR <= {LFSR[1:0], LFSR[2] ^ LFSR[0]};
    end
    
    assign LFSR_out = LFSR;
endmodule

collision.v

`timescale 1ns / 1ps
`include "constants.vh"

module collision(
    input sclk,
    input reset,
    input wire [23:0] shifted_display_state,
    input wire [2:0] player_state,
    output reg [23:0] combined_state
    );
    reg game_over;
    always @(posedge sclk or posedge reset) begin
        if (reset) begin
            combined_state <= `RESET_STATE;
            game_over <= 1'b0;
        end else if (game_over) begin
            combined_state <= `GAME_OVER;
        end else if (shifted_display_state[14:12] == `OBSTACLE_STATE) begin
            if (player_state == `PLAYER_AIR_STATE) begin
                combined_state <= {shifted_display_state[23:15], `PLAYER_BOX_JUMP_STATE, shifted_display_state[11:0]};
            end else begin
                combined_state <= `GAME_OVER;
                game_over <= 1'b1;
            end
        end else begin
                combined_state <= {shifted_display_state[23:15], player_state, shifted_display_state[11:0]};
        end
    end  
endmodule

seven_segment_top.v

`timescale 1ns / 1ps
`include "constants.vh"

module seven_segment_top(
    input clk,
    input [23:0] display_game_state,
    output [6:0] sseg_out,
    output reg [7:0] an_out
    );
    
    // hold value of timer before switching to next 
    reg [16:0] an_count;
    reg [2:0] an_select;
    reg [2:0] display_select;
    
        
    sseg_decoder SS0(.state(display_select), .sseg_out(sseg_out));
    // 100 MHz / 100000 = 1 ms multiplexing
    always@(posedge clk) begin
        if (an_count >= 32'd99999) begin
            an_count <= 0;
            an_select <= an_select + 1'b1;
        end else
            an_count <= an_count + 1'b1;
    end
    
    // display game state for each segment
    always@(an_select) begin
        case(an_select)
            3'b000: begin
                an_out <= 8'b11111110;
                display_select <= display_game_state[2:0];
            end
            3'b001: begin
                an_out <= 8'b11111101;
                display_select <= display_game_state[5:3];
            end
            3'b010: begin
                an_out <= 8'b11111011;
                display_select <= display_game_state[8:6];
            end
            3'b011: begin
                an_out <= 8'b11110111;
                display_select <= display_game_state[11:9];
            end
            3'b100: begin
                an_out <= 8'b11101111;
                display_select <= display_game_state[14:12];
            end
            3'b101: begin
                an_out <= 8'b11011111;
                display_select <= display_game_state[17:15];
            end
            3'b110: begin
                an_out <= 8'b10111111;
                display_select <= display_game_state[20:18];
            end
            3'b111: begin
                an_out <= 8'b01111111;
                display_select <= display_game_state[23:21];
            end 
        endcase
    end
endmodule

sseg_decoder.v

`timescale 1ns / 1ps

`include "constants.vh"

module sseg_decoder(
    input [2:0] state,
    output reg [6:0] sseg_out
    );
    
    parameter sseg_floor              =  7'b1110111;
    parameter sseg_obstacle           =  7'b1100010;
    parameter sseg_player_floor       =  7'b1110011;
    parameter sseg_player_air         =  7'b1010111;
    parameter sseg_player_box_jump    =  7'b1000010;
    parameter sseg_game_over          =  7'b0000000;
    
         always @(state) begin
            case (state) // display individual character
            `FLOOR_STATE           : sseg_out = sseg_floor;
            `OBSTACLE_STATE        : sseg_out = sseg_obstacle;
            `PLAYER_AIR_STATE      : sseg_out = sseg_player_air;
            `PLAYER_FLOOR_STATE    : sseg_out = sseg_player_floor;
            `PLAYER_BOX_JUMP_STATE : sseg_out = sseg_player_box_jump;
            `GAME_OVER_STATE       : sseg_out = sseg_game_over;

            //switch off 7 segment character 
            default : sseg_out = 7'b1111111; 
            endcase
            end
endmodule

constants.vh

`ifndef CONSTANTS_VH
`define CONSTANTS_VH

`define FLOOR_STATE             3'b000
`define OBSTACLE_STATE          3'b001
`define PLAYER_AIR_STATE        3'b010
`define PLAYER_FLOOR_STATE      3'b011
`define GAME_OVER_STATE         3'b100
`define PLAYER_BOX_JUMP_STATE   3'b111

`define RESET_STATE             24'b000_000_000_011_000_000_000_000
`define SHIFT_RESET_STATE       24'b000_000_000_000_000_000_000_000
`define GAME_OVER               24'b100_100_100_100_100_100_100_100

`endif

collision_tb.v

`timescale 1ns / 1ps

module collision_tb(

    );
    reg sclk;
    reg reset;
    reg button;
    
    wire [2:0] player_state;
    wire [23:0] shifted_game_state;
    wire [23:0] combined_state;
    
    input_handler player(.sclk(sclk), .reset(reset), .button(button), .player_state(player_state));
    game_shift shift(.sclk(sclk), .reset(reset), .shifted_game_state(shifted_game_state));
    collision col(.sclk(sclk), .reset(reset), .shifted_display_state(shifted_game_state), 
         .player_state(player_state), .combined_state(combined_state));
    
    always begin
        sclk = 1'b0; #10;
        sclk = 1'b1; #10;
    end
    
    initial begin
        reset = 1'b1; button = 1'b0; #30;
        reset = 1'b0; button = 1'b0; #30;
        
        button = 1'b1; #50;
        button = 1'b0; #100;
                
        button = 1'b1; #50;
        button = 1'b0; #50;
        button = 1'b1; #50;

    end
endmodule