--- Code for LSU EE 4702 Spring 2001 --- Calculator Example library ieee; use ieee.std_logic_1164.all; library Std_DevelopersKit; use Std_DevelopersKit.Std_Regpak.all; --- Definitions used by calculator code and testbench. package calc_defs is type key_t is array ( 5 downto 0 ) of std_logic; -- These must be initialized by string literals to be used in a case stmt. constant key_none : key_t := o"00"; constant key_never : key_t := o"01"; constant key_plus : key_t := o"10"; constant key_minus : key_t := o"11"; constant key_times : key_t := o"12"; constant key_divide : key_t := o"13"; constant key_equal : key_t := o"14"; constant key_clear : key_t := o"15"; constant key_0 : key_t := o"20"; constant key_1 : key_t := o"21"; constant key_2 : key_t := o"22"; constant key_3 : key_t := o"23"; constant key_4 : key_t := o"24"; constant key_5 : key_t := o"25"; constant key_6 : key_t := o"26"; constant key_7 : key_t := o"27"; constant key_8 : key_t := o"30"; constant key_9 : key_t := o"31"; end calc_defs; --- Calculator library ieee; use ieee.std_logic_1164.all; library Std_DevelopersKit; use Std_DevelopersKit.Std_Regpak.all; use work.calc_defs.all; entity calc is generic( precision: integer := 32 ); port( display_val : out std_logic_vector ( precision-1 downto 0 ); beep : out std_logic; key_code : in key_t; reset : in std_logic; clk : in std_logic); end calc; architecture a1 of calc is -- Internally used constants for categorizing keys. constant kty_digit: key_t := o"40"; constant kty_arith: key_t := o"41"; -- Other constants. constant buffer_max:integer := ( 2 ** precision ) - 1; constant zero: std_logic_vector ( precision-1 downto 0 ) := ( others => '0' ); type state_t is (st_0N, st_0P, st_0C, st_1N, st_1P); signal beep_time : std_logic_vector ( 5 downto 0 ); signal beep_ack, beep_req : std_logic; signal pending_op : key_t; signal state : state_t; signal cbuffer, acc : std_logic_vector ( precision-1 downto 0 ); impure function do_op return std_logic_vector is begin case pending_op is when key_plus => return acc + cbuffer; when key_minus => return acc - cbuffer; when key_times => return acc * cbuffer; when key_divide => if cbuffer = zero then return zero; else return acc / cbuffer; end if; when others => assert false report "Error in behavioral description." severity failure; return zero; -- Pacify compiler. end case; end function; procedure fatal (constant message:in string) is begin report "Error in behavioral description: " & message; assert false report "Execution stopping." severity failure; end procedure; -- Set a std_logic_vector signal to zero. procedure clr (signal a :inout std_logic_vector) is begin for i in a'range loop a(i) <= '0'; end loop; end; -- Set a std_logic_vector signal to an integer. procedure set(signal a: inout std_logic_vector; constant i: in integer) is begin a <= to_stdlogicvector(i,a'length); end; begin display_val <= cbuffer; -- Turn beep on when command by other process and off when timer -- reaches zero. process begin wait until falling_edge(clk); if reset = '1' then beep_ack <= '0'; beep <= '0'; clr(beep_time); elsif ( beep_ack xor beep_req ) = '1' then beep_ack <= not beep_ack; set(beep_time,20); beep <= '1'; else if beep_time /= zero then beep_time <= beep_time - 1; else beep <= '0'; end if; end if; end process; process variable nl: std_logic; variable key_type: key_t; -- Key category. -- Note: next_state a variable because signals updated at end of time step. variable next_state: state_t; procedure add_digit is begin if cbuffer < buffer_max then cbuffer <= cbuffer * 10 + std_logic_vector(key_code) - std_logic_vector(key_0); end if; end procedure; procedure do_beep is begin beep_req <= not beep_req; next_state := state; end procedure; procedure do_clear is begin clr(acc); clr(cbuffer); next_state := st_0N; end procedure; begin wait until rising_edge(clk); if reset = '1' then beep_req <= '0'; nl := '0'; state <= st_0N; clr(cbuffer); clr(acc); pending_op <= key_never; elsif key_code = key_none then nl := '1'; elsif nl = '1' then nl := '0'; case key_code is when key_0 | key_1 | key_2 | key_3 | key_4 | key_5 | key_6 | key_7 | key_8 | key_9 => key_type := kty_digit; when key_plus | key_minus | key_times | key_divide => key_type := kty_arith; when others => key_type := key_code; end case ; case state is when st_0N => case key_type is when kty_digit => add_digit; next_state := st_0P; when key_clear => do_clear; when others => do_beep; end case; when st_0P => case key_type is when kty_digit => add_digit; next_state := state; when kty_arith => pending_op <= key_code; acc <= cbuffer; clr(cbuffer); next_state := st_1N; when key_clear => do_clear; when others => do_beep; end case; when st_0C => case key_type is when kty_digit => clr(cbuffer); wait for 0 ns; add_digit; next_state := st_0P; when kty_arith => pending_op <= key_code; acc <= cbuffer; clr(cbuffer); next_state := st_1N; when key_clear => do_clear; when others => do_beep; end case; when st_1N => case key_type is when kty_digit => add_digit; next_state := st_1P; when key_clear => do_clear; when others => do_beep; end case; when st_1P => case key_type is when kty_digit => add_digit; next_state := state; when key_equal => cbuffer <= do_op; next_state := st_0C; when kty_arith => acc <= do_op; pending_op <= key_code; clr(cbuffer); next_state := st_1N; when key_clear => do_clear; when others => do_beep; end case; when others => fatal("Unknown case."); end case; state <= next_state; end if; end process; end a1; --- Calculator Testbench (Demo, not really a test.) library ieee; use ieee.std_logic_1164.all; library Std_DevelopersKit; use Std_DevelopersKit.Std_Regpak.all; use Std_DevelopersKit.Std_IOpak.all; use work.calc_defs.all; entity calctb is end; architecture a1 of calctb is constant prec : integer:= 30; signal display : std_logic_vector ( prec-1 downto 0 ); signal key : key_t; signal clk, reset, beep : std_logic:= '0'; begin c:entity work.calc(a1) generic map (prec) port map (display,beep,key,reset,clk); clk <= not clk after 2 ns; process(beep) begin if beep = '1' then report "Beep starting."; elsif beep = '0' then report "Beep finished."; end if; end process; process variable initialized: integer:= 0; type key_array_t is array ( character'low to character'high ) of key_t; variable to_key: key_array_t; procedure command (constant cmd: in string) is variable c: character; begin if initialized /= 1 then for i in to_key'range loop to_key(i) := key_never; end loop; for i in 0 to 9 loop to_key( character'val((i+character'pos('0'))) ) := key_t(std_logic_vector(key_0) + i); end loop; to_key('+'):= key_plus; to_key('-'):= key_minus; to_key('/'):= key_divide; to_key('*'):= key_times; to_key('='):= key_equal; to_key('c'):= key_clear; to_key(' '):= key_none; to_key(character'val(0)):= key_none; initialized:= 1; end if; for i in cmd'range loop c:= cmd(i); wait until rising_edge(clk); wait until falling_edge(clk); key <= to_key( c ); wait until rising_edge(clk); wait until falling_edge(clk); assert key /= key_never report "Demo error: illegal key in command: " & to_string(c) & c severity failure; assert key = key_none report "Key " & c & " Display " & to_string(to_integer(display)) severity note; wait until rising_edge(clk); wait until falling_edge(clk); key <= key_none; end loop; end procedure; begin reset <= '0'; for i in 0 to 1 loop wait until falling_edge(clk); end loop; reset <= '1'; for i in 0 to 1 loop wait until falling_edge(clk); end loop; reset <= '0'; for i in 0 to 1 loop wait until falling_edge(clk); end loop; command("c 5 c 12 + 34 = "); command(" 1 + 2 + 3 ++ 4 = - 10 = "); assert false report "Done with tests" severity failure; end process; end a1;