library ieee; use ieee.std_logic_1164.all; ENTITY dice IS PORT( clock : IN STD_LOGIC; --system clock reset : IN STD_LOGIC; --system reset key1, key2, key3, key4, key5, key6, key7, key8, key9, key_enter, key_roll : IN STD_LOGIC; -- keys on the keypad dice1, dice2, dice3, dice4, dice5, dice6 : OUT INTEGER RANGE 0 to 20 --integers representing value on dice when key_roll is pressed while in the correct state -- these values will be converted to pseudo ASCII for output by chip(.vhd) ); END dice; ARCHITECTURE behavior OF dice IS SUBTYPE dice_number_type IS integer RANGE 1 TO 20; --maximum number of dice SIGNAL dice_number : dice_number_type; -- number of dice 1 to 6 SUBTYPE dice_sides_type IS integer RANGE 2 to 20; -- maximum # of sides on a dice SIGNAL dice_sides : dice_sides_type; -- number of sides 2 to 20 TYPE state_type IS (reset_state, choose_num, choose_num2, num_sides, num_sides2, roll_dice); -- state machine states SIGNAL state : state_type; --current state the circuit is in SIGNAL next_state : state_type; --next state circuit will go to (on next clock rising edge) SIGNAL num_enable, num_ack, sides_enable, sides_ack : STD_LOGIC; -- enables going to the next state from a state that requires extra inputs besides 'enter' SUBTYPE counter_number IS integer RANGE 1 to 20; SIGNAL dice1_counter, dice2_counter, dice3_counter, dice4_counter, dice5_counter, dice6_counter : counter_number; -- these are cascaded counters that cycle -- through all possible dice combinations at the clock speed BEGIN state_machine : process --(clock) BEGIN CASE state IS WHEN reset_state => -- when reset is pressed this state will be entered num_ack <= '0'; -- valid # of dice has yet to be entered sides_ack <= '0'; -- valid # of sides has yet to be entered IF reset ='0' THEN next_state <= choose_num; -- ELSE next_state <= reset_state; END IF; WHEN choose_num => IF key_enter = '1' AND num_enable = '1' THEN -- if key_enter is pressed and a valid number has been input num_ack <= '1'; -- set num_ack (valid # of dice has been entered) next_state <= choose_num2; -- advance to next state ELSE next_state <= choose_num;-- otherwise stay in this state END IF; WHEN choose_num2 => IF key_enter = '0' THEN -- stays in this state until key_enter is released -- (avoids taking 1 keystroke as multiple inputs) sides_ack <= '0'; -- valid # of sides has yet to be entered next_state <= num_sides; ELSE next_state <= choose_num2; END IF; WHEN num_sides => IF key_enter = '1' AND sides_enable = '1' THEN -- if key_enter is pressed and a valid number has been input sides_ack <= '1'; -- set num_ack (valid # of sides has been entered) next_state <= num_sides2; ELSE next_state <= num_sides;-- otherwise stay in this state END IF; WHEN num_sides2 => IF key_enter = '0' THEN -- stays in this state until key_enter is released -- (avoids taking 1 keystroke as multiple inputs) next_state <= roll_dice; ELSE next_state <= num_sides2; END IF; WHEN roll_dice => -- number of dice and dice sides have been set and ready to count next_state <= roll_dice; -- never leaves this state (unless reset is pressed) WHEN OTHERS => next_state <= reset_state;-- if an unknown state is encountered, go to reset state END CASE; END PROCESS state_machine; -- ***************** state_register : PROCESS (clock)-- advances the state machine on the clock pulse BEGIN IF reset = '1' THEN -- asynch reset input synchronously resets state machine at next clock pulse state <= reset_state; ELSIF rising_edge(clock) THEN -- rising edge of clock triggers transition to next state of state machine state <= next_state; END IF; END PROCESS state_register; -- **************** choose_number : PROCESS -- enables user to choose the number of dice to roll BEGIN IF state = reset_state THEN num_enable <= '0'; -- resets enable so a valid number must be pressed -- before state machine can advance dice_number <= 0; ELSIF state = choose_num THEN-- only valid when state machine is in choose_num IF key1 = '1' THEN -- the following lines correlate keypresses to # of dice dice_number <= 1; -- " ELSIF key2 = '1' THEN -- " dice_number <= 2; -- " ELSIF key3 = '1' THEN -- " dice_number <= 3; -- " ELSIF key4 = '1' THEN -- " dice_number <= 4; -- " ELSIF key5 = '1' THEN -- " dice_number <= 5; -- " ELSIF key6 = '1' THEN -- " dice_number <= 6; -- " END IF; -- " IF dice_number > 0 AND dice_number < 7 THEN -- if dice number has been set to a valid value num_enable <= '1'; -- enable is set to allow state machine to advance END IF; END IF; END PROCESS choose_number; -- ********************** number_of_sides : PROCESS -- enables user to choose the number of dice to roll BEGIN IF state = reset_state THEN sides_enable <= '0'; -- resets enable so a valid number must be pressed dice_sides <= 0; ELSIF state = choose_num2 THEN sides_enable <= '0'; -- resets enable so a valid number must be pressed -- before state machine can advance ELSIF state = num_sides THEN -- only valid when state machine is in num_sides IF key2 = '1' THEN -- the following lines correlate keypresses to # of dice sides dice_sides <= 2; -- " ELSIF key3 = '1' THEN -- " dice_sides <= 3; -- " ELSIF key4 = '1' THEN -- " dice_sides <= 4; -- " ELSIF key5 = '1' THEN -- " dice_sides <= 5; -- " ELSIF key6 = '1' THEN -- " dice_sides <= 6; -- " -- ELSIF key7 = '1' THEN -- " -- sides only go to 6 -- dice_sides <= 7; -- " -- ELSIF key8 = '1' THEN -- " -- dice_sides <= 8; -- " -- ELSIF key9 = '1' THEN -- " -- dice_sides <= 9; -- " END IF; -- " IF dice_sides > 1 AND dice_sides < 7 THEN -- if dice sides has been set to a valid value sides_enable <= '1'; -- enable is set to allow state machine to advance END IF; END IF; END PROCESS number_of_sides; -- ********************** roll_the_dice : PROCESS(clock, reset) -- puts the counter in motion to instantiate -- the random dice values BEGIN IF reset = '1' THEN dice1_counter <= 1; dice2_counter <= 1; dice3_counter <= 1; dice4_counter <= 1; dice5_counter <= 1; dice6_counter <= 1; ELSIF rising_edge(clock) THEN IF state = roll_dice THEN -- if the state machine is in roll_dice -- (and rising edge of clock detected) IF dice1_counter >= dice_sides THEN -- if dice1_counter equal or bigger than dice_sides dice1_counter <= 1; --reset dice1_counter IF dice2_counter >= dice_sides THEN -- if dice2_counter equal or bigger than dice_sides dice2_counter <=1; --reset dice2_counter IF dice3_counter >= dice_sides THEN -- if dice3_counter equal or bigger than dice_sides dice3_counter <=1; --reset dice3_counter IF dice4_counter >= dice_sides THEN -- if dice4_counter equal or bigger than dice_sides dice4_counter <=1; --reset dice4_counter IF dice5_counter >= dice_sides THEN -- if dice5_counter equal or bigger than dice_sides dice5_counter <=1; --reset dice5_counter IF dice6_counter >= dice_sides THEN -- if dice6_counter equal or bigger than dice_sides dice6_counter <=1; --reset dice6_counter ELSE dice6_counter <= dice6_counter + 1; END IF; -- else incerment dice6_counter ELSE dice5_counter <= dice5_counter + 1; END IF; -- else incerment dice5_counter ELSE dice4_counter <= dice4_counter + 1; END IF; -- else incerment dice4_counter ELSE dice3_counter <= dice3_counter + 1; END IF; -- else incerment dice3_counter ELSE dice2_counter <= dice2_counter + 1; END IF; -- else incerment dice2_counter ELSE dice1_counter <= dice1_counter + 1; END IF; -- else incerment dice1_counter END IF; END IF; END PROCESS roll_the_dice; -- ********************* assign_the_dice : PROCESS (key_roll, reset) -- assigns a value from the dice counter -- to dice when rising edge of key_roll is detected BEGIN IF reset = '1' THEN dice1 <= 0; -- always at least one die dice2 <= 0; -- set all others to zero dice3 <= 0; -- " dice4 <= 0; -- " dice5 <= 0; -- " dice6 <= 0; -- " -- WAIT UNTIL rising_edge(key_roll); -- active only on rising edge of key_roll -- IF key_roll = '1' THEN ELSIF (key_roll = '0') THEN -- active only on rising edge of key_roll IF state = roll_dice THEN -- active only when state machine is in roll_dice CASE dice_number IS WHEN 1 => dice1 <= dice1_counter; dice2 <= dice2_counter; dice3 <= dice3_counter; dice4 <= dice4_counter; dice5 <= dice5_counter; dice6 <= dice6_counter; -- set the second dice output to its new value WHEN 2 => -- if there are two dice selected dice1 <= dice1_counter; dice2 <= dice2_counter; -- set the second dice output to its new value dice3 <= 0; dice4 <= 0; dice5 <= 0; dice6 <= 0; WHEN 3 => -- if there are three dice selected dice1 <= dice1_counter; dice2 <= dice2_counter; dice3 <= dice3_counter; -- set the second dice output to its new value dice4 <= 0; dice5 <= 0; dice6 <= 0; WHEN 4 => -- if there are four dice selected dice1 <= dice1_counter; dice2 <= dice2_counter; dice3 <= dice3_counter; dice4 <= dice4_counter; -- set the second dice output to its new value dice5 <= 0; dice6 <= 0; WHEN 5 => -- if there are five dice selected dice1 <= dice1_counter; dice2 <= dice2_counter; dice3 <= dice3_counter; dice4 <= dice4_counter; dice5 <= dice5_counter; -- set the second dice output to its new value dice6 <= 0; WHEN 6 => -- if there are six dice selected dice1 <= dice1_counter; dice2 <= dice2_counter; dice3 <= dice3_counter; dice4 <= dice4_counter; dice5 <= dice5_counter; dice6 <= dice6_counter; -- set the second dice output to its new value WHEN OTHERS => dice1 <= 0; dice2 <= 0; dice3 <= 0; dice4 <= 0; dice5 <= 0; dice6 <= 0; -- set the second dice output to its new value END CASE; END IF; END IF; END PROCESS assign_the_dice; -- ***************** -- ************************** END behavior;