/* * This code implements a game of ping pong (table tennis) between 2 players, with * a slight twist: each player puts a ball into play at the same time. There can * be an indefinite delay from the time one player hits a ball until the time that * the other player returns it. If both balls are in play, then both players * always hit each ball at the same instant. * * While both balls are in play, exactly one player may choose not to return his * ball. This leaves one ball in play. If just one ball is in play, the ball * should remain in play forever. */ typedef enum {BALL, NO_BALL} player_status; typedef enum {HIT, NO_HIT} action_type; module ping_pong(clk); input clk; /* signal declarations */ action_type wire action_A, action_B; player_status wire state_A, state_B; /* the ping pong players */ player player_A(clk, action_B, action_A, state_A); player player_B(clk, action_A, action_B, state_B); never_no_balls nnb(clk, state_A, state_B); infinitely_often_hit ioh(clk, action_A); endmodule /* * Two state process. If the player doesn't have the ball (state NO_BALL) and the * opponent hits the ball, then go to state BALL. If the player has the ball, then * if he doesn't hit the ball, then he remains in state BALL. If he hits the ball, * and the opponent doesn't also hit the ball, then go to state NO_BALL. */ module player(clk, opponent, me, state); input clk; input opponent; output me; output state; action_type wire opponent, me, random; player_status reg state; initial state = BALL; /* set the value of the output of the player */ assign random = $ND(HIT, NO_HIT); assign me = (state == BALL) ? random : NO_HIT; always @(posedge clk) begin case(state) BALL: begin if ((me == HIT) && (opponent == NO_HIT)) state = NO_BALL; end NO_BALL: begin if (opponent == HIT) state = BALL; end default:; endcase; end endmodule /* * If it's ever the case that neither player has a ball, then go to state BAD * and stay there. */ typedef enum {GOOD, BAD} prop1_status; module never_no_balls(clk, state_A, state_B); input clk; input state_A; input state_B; player_status wire state_A, state_B; prop1_status reg state; initial state = GOOD; always @(posedge clk) begin case(state) GOOD: begin if ((state_A == NO_BALL) && (state_B == NO_BALL)) state = BAD; end BAD: begin state = BAD; end default:; endcase; end endmodule /* * If player does not hit the ball now, then he will sometime in the future. */ typedef enum {OKAY, PENDING} prop2_status; module infinitely_often_hit(clk, player_action); input clk; input player_action; action_type wire player_action; prop2_status reg state; initial state = OKAY; always @(posedge clk) begin case(state) OKAY: begin if (player_action == NO_HIT) state = PENDING; end PENDING: begin if (player_action == HIT) state = OKAY; end default:; endcase; end endmodule