lecture 9 chap 11: subprograms instructors: fu-chiung cheng ( 鄭福炯 ) associate professor...

Post on 29-Jan-2016

227 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Lecture 9Chap 11: Subprograms

Instructors: Fu-Chiung Cheng

(鄭福炯 )Associate Professor

Computer Science & EngineeringTatung University

Subprograms

• Subprograms in VHDL are very much like subprograms in software programming languages. • Subprograms contain sequences of sequential statements and can be called from anywhere in VHDL model.• Subprograms form hierarchy.• Two types of subprograms:

ProcedureFunction

Functions

• A function is a subprogram that can be called in an expression.• Function declaration: function carry(bit1, bit2, bit3: in std_logic) return std_logic is variable result: std_logic;begin result:=(bit1 and bit2) or (bit1 and (bit3) or (bit2 and bit3); return result;end;

Functions

function_body ::= function identifier

[ [ parameter_interface_list ]] return type_mark is{{ subprogram_declarative_part }}

begin{ { sequential statement }}

end [[ function ] [ ] [ identifier ] ] ;

function_declaration ::= function identifier

[ [ parameter_interface_list ]] return type_mark ;

Functions

• Functions should be declared before they can be called. • Functions can be declared in A. declaration part of a process. B. declaration part of an architecture. C. package.

Calling a function

• Ex1 library ieee; use ieee.std_logic_1164.all; entity carry_example is

port (a, b, c: in std_logic; cout: std_logic); end; architecture behavior of carry_example is

-- declare functions in here if necessary begin

cout <= carry(a,b,c); end;

Calling a function

• Ex2

process(a,b,c) -- declare functions in here if necessary

begincout <= carry(a,b,c);

end process;

Return of a function

function carry(bit1, bit2, bit3: in std_logic) return std_logic is variable result: std_logic;begin result:=(bit1 and bit2) or (bit1 and (bit3) or (bit2 and bit3); return result;end; -- return is the output of this circuitfunction carry(bit1, bit2, bit3: in std_logic) return std_logic isbegin return (bit1 and bit2) or (bit1 and (bit3) or (bit2 and bit3);end;

Function: initial values

function to_bit(a: in boolean) return bit is variable result: bit:=‘0’; -- reinitialized at call begin if a then

result := ‘1’; end if; return result;end;function to_bit(a: in boolean) return bit is variable result: bit:= bit’val(boolean’pos(a)); begin -- a = true ==> boolean’pos(true) = 1 return result; -- a = false ==> boolean’pos(false)=0end; -- bit’val(0)=‘0’ and bit’val(1)=‘1’;

Function: initial values

function to_bit(a: in boolean) return bit is variable result: bit;begin result := bit’val(boolean’pos(a)); return result;end;

function to_bit(a: in boolean) return bit isbegin return bit’val(boolean’pos(a)); end;

Functions with Unconstrained Parameters

• One of the most useful features of functions is the ability to define them with unconstrained array as parameters.• Note that when this function is called, a new copy (circuit) is created and the size is known.• Example:

• vec has type std_logic_vector -- unconstrained array type

Function count_ones(vec : std_logic_vector) return natural is

variable count : natural;begin

count:=0;for i in vec’range loop

if vec(i)=‘1’ thencount:=count+1;

end if;end loop;return count;

end;

library ieee;use ieee.std_logic_1164.all;entity count_top_half is

port (vec: in std_logic_vector (15 downto 0); count: out natural range 0 to 8);

end;

architecture behavior of count_top_half isbegin

count <=count_ones(vec(15 downto 8));end;

Normalization

• To write unconstrained functions, it is essential to make no assumptions at all about the range or directions of the unconstrained array parameter.• “00001111” range ?? A. VHDL: 0 to 7 B. Could be 7 downto 0, 1 to 8 (depend on Synthesis tools)• Normalization: The parameters are immediately assigned to local variables which has the same size as parameters, but with ranges that conform to the common convention.

function count_match (a,b: std_logic_vector) return natural is variable va:std_logic_vector(a’length-1 downto 0):=a; variable vb:std_logic_vector(b’length-1 downto 0):=b; variable count: natural :=0;begin assert va’length = vb’length report “count_matches: parameters must be the same size” severity failue; for i in va’range loop

if va(i) = vb(i) then count := count +1;end if;

end loop; return count;end;

Unconstrained Return Valuesfunction match (a,b: std_logic_vector)

return std_logic_vector is variable va:std_logic_vector(a’length-1 downto 0):=a; variable vb:std_logic_vector(b’length-1 downto 0):=b; variable result: std_logic_vector(a’length-1 downto 0);begin assert va’length = vb’length report “matches: parameters must be the same size” severity failue; for i in va’range loop

result(I) := not(va(I) xor vb(I)); end loop; return result; -- the same size as the input parametersend;

Unconstrained Return Values

library ieee;use ieee.std_logic_1164.all;entity match_bit is

port (a, b: in std_logic_vector (7 downto 0); result: out std_logic_vector (7 downto 0);

end;

architecture behavior of match_bit isbegin

result <=matches(a, b);end;

Unconstrained Return Valuesfunction extend (a: std_logic_vector, size: natural)

return std_logic_vector is variable va:std_logic_vector(a’length-1 downto 0):=a; variable result: std_logic_vector(size-1 downto 0);begin assert va’length <= size report “Extend: must extend to a longer length” severity failue; assert va’length >=1 report “Extend: must at least one bit” severity failue; result := (others ==> va(va’left)); result(va’range) := va; return result; -- may not be the same size as inputsend;

Unconstrained Return Values

library ieee;use ieee.std_logic_1164.all;entity extend_ex is

port (a: in std_logic_vector (7 downto 0); z: out std_logic_vector (15 downto 0);

end;

architecture behavior of extend_ex isbegin

z <=extend(a, 16);end;

Multiple Returns: ex1

function count_trailing (vec: std_logic_vector) return natural is

variable result: natural :=0;begin for i in vec’reverse_range loop if vec(I) = ‘1’ then

return result; end if;

result := result + 1; end loop; return result; end;

Multiple Returns: ex2

function to_char (a: std_logic) return character isbegin case a is

when ‘U’ ==> return ‘U’;when ‘X’ ==> return ‘X’;when ‘0’ ==> return ‘0’;when ‘1’ ==> return ‘1’;when ‘Z’ ==> return ‘Z’;when ‘W’ ==> return ‘W’;when ‘L’ ==> return ‘L’;when ‘H’ ==> return ‘H’;when ‘-’ ==> return ‘-’;

end case;end;

Function Overloading

• Overloading functions:functions with different signatures.

• Signature: number of parameters and typesDifferent parameter typesDifferent number of parameters

• Example:procedure increment ( a : inout integer ;

n : in integer := 1) is . . .procedure increment ( a : inout bit_vector ;

n : in bit_vector := b? ) is . . .procedure increment ( a : inout bit_vector ;

n : in integer := 1 ) is . . .

Operator

• Operators in VHDL are functions with infix notation. Z <= a + b * c;• Built-in operators and Operator overloading: see table 11.1 pp 240.• Unary operators: function “not” (r: type) return type; function “-” (r: type) return type; function “+” (r: type) return type; function “abs” (r: type) return type;

Operator

• Binary operators: function “and” (l, r: type) return type; -- or, nand, nor, xor, xnor function “=” (l, r: type) return boolean; -- /=, <, <=, >, >= function “sll” (l, r: type) return type; -- srl, sla, sra, rol, ror function “**” (l, r: type) return type; -- *, /, mod, rem, +, -, & function “&” (l: type, r: element) return type; function “&” (l: element, r: type) return type; function “&” (l: element, r: element) return type;

Type Conversion

• Built-in type Conversions A. Closely-related types conversion: integer signal sh: short; signal int: natural; … int <= natural(sh); B. Array types under the following conditions:

1. Same number of dimensions (one dimension only).2. Elements are of the same type3. Indexed by types which can be converted to each other (natural vs enumerate type not ok).

Type Conversion

• User-defined type conversion:

function to_bit (arg: boolean) return bit is begin case arg is

when true => return ‘1’;when false => return ‘0’;

end case;end;

function to_bit (arg: std_logic) return bit is begin case arg is

when ‘1’ => return ‘1’;when others => return ‘0’;

end case;end;function to_bit (arg: std_logic) return bit is begin case arg is

when ‘1’ => return ‘1’;when ‘0’ => return ‘0’;when others =>

assert false report “conversion error”severity warning;return ‘0’;

end case;end;

function to_std_logic_ vector (arg: integer: size: natural) return std_logic_vector is

variable v: integer:=arg; constant negative : boolean := arg <0; variable result: std_logic_vector(size-1 downto 0);begin if negative then v:=-(V+1); end if; for count in 0 to size -1 loop

if (v rem 2) =1 then result(count):=‘1’else result(count):=‘0’;end if;v = v/2;

end loop; if negative then result := not result; end if ; end;

Procedures

• Procedures and functions are subprograms.• Procedures look very like functions.• The difference: A. parameters of a procedure can be of mode in, out, inout. in: pass a value into a procedure out: pass a value out of a procedure (return value) inout: pass a value into a procedure, modify it, and pass back again. B. Procedures do not have return values.

Procedures

• Procedures and functions are subprograms.• Procedures look very like functions.• The difference: A. parameters of a procedure can be of mode in, out, inout. in: pass a value into a procedure out: pass a value out of a procedure (return value) inout: pass a value into a procedure, modify it, and pass back again. B. Procedures do not have return values.

Procedure: Example

procedure fullAdder (a, b, c: in std_logic;sum, cout: out std_logic ) is

beginsum:=a xor b xor c;cout:=(a and b) or (a and c) or (b and c);

end;

• Note that assignments used in the procedure are variable assignment.• This is because out parameters on a procedure are variable by default.• Signal parameters can also be specified.

library ieee; use ieee.std_logic_1164.all;

entity adder4 is port ( a, b: in std_logic_vector (3 downto 0); cin : in std_logic;

sum: out std_logic_vector (3 downto 0);cout: out std_logic);

end;

architecture behavior of adder4 isbegin process(a,b,cin)

variable result: std_logic_vector (3 downto 0);variable carry: std_logic;

beginfullAdder(a(0), b(0), cin, result(0), carry);fullAdder(a(1), b(1), carry, result(1), carry);fullAdder(a(2), b(2), carry, result(2), carry);fullAdder(a(3), b(3), carry, result(3), carry);sum <=result;cout <= carry;

end process;end;

Procedure:

• The procedure can only be used in a sequential procedure call, because the out parameters are variables.• Variable carry is both the input and output of procedure calls (the second, third and fourth full_adders)• The value of carry is passed in first, then the procedure is executed, calculating a new carry output and then carry is passed back out.• Summary: A. variables: result, carry, sum and cout of fullAdder B. signals: a, b, cin, sum and cout of adder4.

Procedure with Unconstrained Parameters

• Procedures can also be declared with unconstrained parameters in the same way as functions.• Example: A. the parameters all take on the range 7 downto 0. B. Need normalization as functions.

procedure add(a,b: in std_logic_vector;sum: out std_logic_vector);

…library ieee; use ieee.std_logic_1164.all;entity add_ex is

port ( a, b: in std_logic_vector (7 downto 0);sum: out std_logic_vector (7 downto 0));

end;architecture behavior of add_ex isbegin process(a,b)

variable result: std_logic_vector (7 downto 0); begin

add(a, b, result);sum <=result;

end process;end;

procedure add(a,b: in std_logic_vector;sum: out std_logic_vector); is

variable a_int: std_logic_vector(a’length-1 downto 0):=a; variable b_int: std_logic_vector(b’length-1 downto 0):=b; variable sum_int: std_logic_vector(sum’length-1 downto 0); variable carry: std_logic := ‘0’;begin assert a_int’length = b_int’length

report “inputs must be same length” severity failure; assert sum_int’length = a_int’length

report “in and out must be same length” severity failure; for I in a_int’range loop

sum_int(I) :=a_int(I) xor b_int(I) xor carry;carry := (a_int(I) and b_int(I)) or (a_int and carry) or

(b_int(I) and carry); end loop; sum := sum_int;end;

Procedures with unconstrained parameters

• The assertions check that the parameters are the same length.• Sum in add is of mode out and thus it is unreadable. • However, the attribute of out parameters are accessible.

Procedure: inout parameters

• An inout parameter is a parameter that can be modified by the procedure (read/write).• It is not equivalent to bidirectional or a tristate signal.• Example:

procedure invert(arg: inout std_logic_vector) isbegin

for I in arg’range looparg(I) := not arg(I);

end loop;end;

• This can be normalized.

Procedure: inout parameters

• Normalization example:procedure invert(arg: inout std_logic_vector) is

variable arg_int: std_logic_vector(arg’length-1 down 0):=arg;

beginfor I in arg_int’range loop

arg_int(I) := not arg_int(I);end loop;arg := arg_int;

end;

Procedure: Signal Parameters

• A subprogram parameter has three modes: in, out, inout.

• A subprogram parameter has three classes: constant, variable, signal.

• Note that A. constant out makes no sense. B. Function parameters may only be of mode in with any class.

Procedure: Signal Parameters

• Default values: A. in parameters: constant B. out and inout parameters: variable.• In parameters may be declared as variable or signal, but this is rarely done in practice. • Out and inout parameters can be declared as signal. (Thus procedures may be used in sequential or

concurrent VHDL.)• Example

Procedure: Signal Parameters

procedure fullAdderS(a, b, c: in std_logic;signal sum, cout: out std_logic ) is

beginsum<=a xor b xor c;cout<=(a and b) or (a and c) or (b and c);

end;

• The out parameters (sum, cout) have been changed to class signal.• In parameters (a, b, c ) are of class constant and can be associated with either signals or variables. • Using signal assignments instead of variables.

library ieee; use ieee.std_logic_1164.all;entity adder4 is port (a, b: in std_logic_vector (3 downto 0);

cin : in std_logic; sum: out std_logic_vector (3 downto 0); cout: out std_logic);

end;

architecture behavior of adder4 issignal c: std_logic_vector (2 downto 0);

beginfullAdderS(a(0), b(0), cin, result(0), c(0));fullAdderS(a(1), b(1), c(0), result(1), c(1));fullAdderS(a(2), b(2), c(1), result(2), c(2));fullAdderS(a(3), b(3), c(2), result(3), cout);

end;

Procedure: Signal Parameters

• The procedures have been used as concurrent procedure calls (no process).• A concurrent procedure call will be re-evaluated every time one of its inputs changes.• Each procedure call is equivalent to

process (a(I), b(I), c(I-1))begin

fullAdderS(a(I), b(I), c(I-1), sum(I), c(I));end process;

Declaring Subprograms:

• Subprograms can be declared in A. declaration part of a process. B. declaration part of an architecture. C. declaration part of other subprograms D. package. • A subprogram declared in a process can only be used in the process• A subprogram declared locally can only be used locally.• A subprogram declared in a package, can be used else where by importing the package.• Example: functions declared within an architecture and a process.

library ieee; use ieee.std_logic_1164.all;entity carry_ex is port (a, b: in std_logic; cout : out std_logic);end;

architecture behavior of carry_ex isfunction carry(bit1, bit2, bit3: in std_logic)

return std_logic isbegin

return (bit1 and bit2) or (bit1 and bit3) or (bit2 and bit3);

end;begin

cout <= carry(a,b,c)end;

architecture behavior of carry_ex isbegin process(a, b, c)

function carry(bit1, bit2, bit3: in std_logic) return std_logic is

beginreturn (bit1 and bit2) or (bit1 and bit3) or

(bit2 and bit3);end;

begincout <= carry(a,b,c)

end process;end;

Subprograms in Packages:

• Subprograms is used to model common operations.• A set of closed-related subprograms can be collected together in a package and shared by other designers.• A package has two parts: A. package head contains the declarations of the

subprograms. B. package body contains the subprogram body.• Often a package contains a new type, associated with subprograms acting on the type.• Example:

Subprograms in Packages:

• The package header of std_logic_vector_arith package:

library ieee;use ieee.std_logic_1164.all;package std_logic_vector_arith is

function carry(a, b, c : std_logic) return std_logic;function sum(a, b, c : std_logic) return std_logic;procedure fullAdder(a, b, c : in std_logic;

s, cout: out std_logic);end;

package body std_logic_vector_arith is

function carry(a, b, c : std_logic) return std_logic isbegin return (a and b) or (a and c) or (b and c);end;

function sum(a, b, c : std_logic) return std_logic isbegin return a xor b xor c;end

procedure fullAdder(a, b, c : in std_logic; s, cout: out std_logic) is

begin s:=sum(a, b, c); cout := carry(a, b, c);end;

end;

Using Packages:

• Having declared a package, it can be used by placing a use clause before the design unit.• Example: library ieee;use ieee.std_logic_1164.all;entity carry_ex is

port (a, b, c : in std_logic; cout: out std_logic);end;use work.std_logic_vector_arith.all;architecture behavior of carry_ex isbegin

cout <= carry(a,b,c)end;

Using Packages:

• The first part of the use clause, work, refers to the library in which the package to be found.• Work is the current working library • Implicit library:

library work;• The second part of the use clause, std_logic_vector_arith, is the name of the package.• The third part of the use clause, all, is the item or items in that package be used in the design. • All makes everything in the package available for use.

Working Example: Complex Number

• Complex number representation will use the left-hand half of the array as the real part and the right-hand half as the imaginary part.• Creating a Complex Number Package: step A. declaration of the type for complex number

and its subprograms.library ieee;use ieee.std_logic_1164.all;package complex_std is

type complex is array (natural range <>) of std_logic;

end;

library ieee;use ieee.std_logic_1164.all;package complex_std is

type complex is array (natural range <>) of std_logic;

function “not” (r:complex) return complex;function “and” (l,r:complex) return complex;function “or” (r:complex) return complex;function “nand” (r:complex) return complex;function “nor” (r:complex) return complex;function “xor” (r:complex) return complex;

function “=” (l, r:complex) return boolean;function “/=” (l,r:complex) return boolean;function “<” (r:complex) return boolean;….

end;

….function “+” (l, r:complex) return complex;function “-” (l, r:complex) return complex;function “*” (l, r:complex) return complex;function “abs” (r:complex) return complex;function “-” (r:complex) return complex;

function real_part (arg:complex) return signed;function imag_part (arg:complex) return signed;function create (R, I:signed) return complex;function resize (arg:complex;size:natural)

return complex;

end;

Working Example: Complex Number

• By declaring the complex_std type, a set of built-in operators will automatically become available. • See Table 11.1 for the built-in operators.• 4 (non built-in) functions are defined

function real_part (arg:complex) return signed;function imag_part (arg:complex) return signed;function create (R, I:signed) return complex;function resize (arg:complex;size:natural)

return complex• Creating a Complex Number Package: step B. Implement functions declared subprograms.

package body complex_std is -- find max function max(l,r:natural) return natural is begin if l >r then return l; else return r; end if; end; -- create complex number function create(r,i:signed) return complex is constant length : natural :=max(r’length, i’length); variable r_int, i_int: signed(length-1 downto 0); begin r_int:=resize(r,length); i_int:=resize(I,length); return complex(r_int & i_int); end; ….end;

-- get real part of complex number function real_part(arg:complex) return signed is variable arg_int: complex(arg’length-1 downto 0) := arg; begin assert arg’length rem 2 = 0 report “Complex: argument length must be even”

severity failure; return signed(arg_int(arg_int’length-1 downto

arg_int’length/2)); end; -- get image part of complex number function image_part(arg:complex) return signed is variable arg_int: complex(arg’length-1 downto 0) := arg; begin assert arg’length rem 2 = 0 report “Complex: argument length must be even”

severity failure; return signed(arg_int(arg_int’length/2-1 downto 0)); end;

-- equality function “=“(l,r:complex) return boolean is begin return real_part(l) = real_part(r) and

image_part(l) = image_part(r); end; -- inequality function “/=“(l,r:complex) return boolean is begin return not (l = r); end; -- greater smaller ... function “<“(l,r:complex) return boolean is begin assert false

report “Complex: illegal ““<“” operation”severity failure;

return flase; end;

top related