Presentation is loading. Please wait.

Presentation is loading. Please wait.

Lecture 9 Chap 11: Subprograms Instructors: Fu-Chiung Cheng ( 鄭福炯 ) Associate Professor Computer Science & Engineering Tatung University.

Similar presentations


Presentation on theme: "Lecture 9 Chap 11: Subprograms Instructors: Fu-Chiung Cheng ( 鄭福炯 ) Associate Professor Computer Science & Engineering Tatung University."— Presentation transcript:

1 Lecture 9 Chap 11: Subprograms Instructors: Fu-Chiung Cheng ( 鄭福炯 ) Associate Professor Computer Science & Engineering Tatung University

2 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: Procedure Function

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

4 Functions

5 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.

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

7 Calling a function Ex2 process(a,b,c) -- declare functions in here if necessary begin cout <= carry(a,b,c); end process;

8 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 circuit function carry(bit1, bit2, bit3: in std_logic) return std_logic is begin return (bit1 and bit2) or (bit1 and (bit3) or (bit2 and bit3); end;

9 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)=0 end;-- bit’val(0)=‘0’ and bit’val(1)=‘1’;

10 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 is begin return bit’val(boolean’pos(a)); end;

11 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

12 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’ then count:=count+1; end if; end loop; return count; end;

13 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 is begin count <=count_ones(vec(15 downto 8)); end;

14 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.

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

16 Unconstrained Return Values function 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 parameters end;

17 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 is begin result <=matches(a, b); end;

18 Unconstrained Return Values function 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 inputs end;

19 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 is begin z <=extend(a, 16); end;

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

21 Multiple Returns: ex2 function to_char (a: std_logic) return character is begin 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;

22 Function Overloading Overloading functions: functions with different signatures. Signature: number of parameters and types Different parameter types Different 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...

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

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

25 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 type 3. Indexed by types which can be converted to each other (natural vs enumerate type not ok).

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

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

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

29 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.

30 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.

31 Procedure: Example procedure fullAdder (a, b, c: in std_logic; sum, cout: out std_logic) is begin sum:=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.

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

33 architecture behavior of adder4 is begin process(a,b,cin) variable result: std_logic_vector (3 downto 0); variable carry: std_logic; begin fullAdder(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;

34 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.

35 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.

36 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 is begin process(a,b) variable result: std_logic_vector (7 downto 0); begin add(a, b, result); sum <=result; end process; end;

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

38 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.

39 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) is begin for I in arg’range loop arg(I) := not arg(I); end loop; end; This can be normalized.

40 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; begin for I in arg_int’range loop arg_int(I) := not arg_int(I); end loop; arg := arg_int; end;

41 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.

42 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

43 Procedure: Signal Parameters procedure fullAdderS(a, b, c: in std_logic; signal sum, cout: out std_logic) is begin sum<=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.

44 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 is signal c: std_logic_vector (2 downto 0); begin fullAdderS(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;

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

46 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.

47 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 is function carry(bit1, bit2, bit3: in std_logic) return std_logic is begin return (bit1 and bit2) or (bit1 and bit3) or (bit2 and bit3); end; begin cout <= carry(a,b,c) end;

48 architecture behavior of carry_ex is begin process(a, b, c) function carry(bit1, bit2, bit3: in std_logic) return std_logic is begin return (bit1 and bit2) or (bit1 and bit3) or (bit2 and bit3); end; begin cout <= carry(a,b,c) end process; end;

49 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:

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

51 package body std_logic_vector_arith is function carry(a, b, c : std_logic) return std_logic is begin return (a and b) or (a and c) or (b and c); end; function sum(a, b, c : std_logic) return std_logic is begin 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;

52 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 is begin cout <= carry(a,b,c) end;

53 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.

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

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

56 …. 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;

57 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.

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

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

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


Download ppt "Lecture 9 Chap 11: Subprograms Instructors: Fu-Chiung Cheng ( 鄭福炯 ) Associate Professor Computer Science & Engineering Tatung University."

Similar presentations


Ads by Google