--- 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;