with func_sel select ALUout <= '0' & (a OR b) when OPOR, '0' & (a AND b) when OPAND, '0' & (a XOR b) when OPXOR, add_w_carry(a,b,cin) when OPADD, -- where add_w_carry returns a value -- one greater than the size of its inputs XOUT when OTHERS reg_clk: block (rising_edge(clk)) begin ResReg <= guarded ALUout(1 to dout'length); end block; cout <= ALUout(0) after cout_delay; dout <= ResReg after reg_delay;Example
O_bus <= ALU ( A_bus, B_bus, cy_in, ctl.func);In this statement we are ignoring the responsibility of the ALU function to set status flags (like C, S, N, V) because a function can return only one value. If we create
procedure ALU ( X, Y : in bit_vector; Cin : bit; F : out bit_vector; C,S,N,V : out bit; ctl_func : in ALU_ops );then we can invoke the procedure ALU to update the control flags with
ALU ( A_bus, B_bus, O_bus, Qc, C,S, N, V, ctl.func);
label : block ( guard_expression ) begin . . . sig_ident <= guarded waveform(s) . . . end label ;Example: A VERY simple CPU Data Unit
CPU_p0: block ( enable = '0' ) begin A_bus <= guarded Register_file (IR.dest); B_bus <= guarded Register_file (IR.source); O_bus <= ALU ( A_bus, B_bus, ctl.func); end CPU_p0; CPU_p1: block ( enable = '1' ) begin Register_file (IR.dest) <= guarded O_bus; end CPU_p1;This description assumes the earlier definition of the buses and the IR register as bit_vector signals, and Register_file as an array of bit_vector signals. ALU is a function returning a bit_vector value and may have been defined in the declarations part of the architecture.
In the upper block the meaning of the "guard" is that the Abus and Bbus receive the content of theRegister_file only while the enable is low.
In the lower block the Register file is update only while the enable is high.
signal Q : bit_vector ( 0 to REGSIZE-1) register ; signal O_bus : bit_vector ( 0 to 15 ) bus;Signals which are to be the targets of guarded signal assignments must be declared to be either bus or register kind. You should declare these consistent with the way in which you are using the signal.
There is a separate DRIVER for a signal for each process (or concurrent signal assignment statement - of any kind) in which there is an assignment to that signal. For the example above, there will be some combination of five processes / concurrent statements for the five components shown. Correspondingly, there will be five drivers for DATA_BUS.
Each DRIVER is a WAVEFORM -- a list of value/time events waiting to occur to update the value of the signal. Whenever it is time for a signal update to occur, the presence of multiple drivers means that the current value of all the other drivers must be considered by a BUS RESOLUTION function, usually included as part of the TYPE declaration for that kind of signal and stored up in the corresponding package.
The behavior of signals with multiple drivers tends to be technology specific. The most common models are
Example:
subtype OC_bit is Wired_And bit ; Then we can declare signal IRQ : OC_bit ; signal DATA_BUS : array (0 to 7) of OC_bit;Example: In package std_logic_1164, the type declaration for a nine valued std_ulogic is:
type std_ulogic is ('U','X','0','1','W','Z','L','H','-');But we used the resolved logic type std_logic in our example of the ALU. That is declared
The function resolved is described in the package body.
The Wired_And function is declared in the same package where OC_bit was declared:
function Wired_And ( in_driver : in bit_vector ) return bit is variable result : bit := '1'; begin for i in in_driver'range loop if in_driver(i) = '0' then result := '0'; exit; end if; end loop; return result ; end Wired_And;
bb: block ( rising_edge ( clock ) ) Z <= guarded X; end bb;is virtually the same as saying
if rising_edge (clock) then Z <= X; -- where Z has been declared to be a signal -- of kind register.If the RHS signal is a bus, then the bus resolution function must specify what is assigned to the signal if there is no driver (similar to the "else" situation previously discussed).
Example:
function tristate (in_driver : std_logic_vector ) return std_logic is begin if in_driver'length = 0 then return "Z'; else ....
entity Z_Adder is port ( Data_A : in integer_32; Data_B : in integer_32; Data_P : in integer_32; Z : out integer; Data_out : out integer_32; sign_Z, s : out bit; z1, z2 : in bit_vector (0 to 1); Z_op, zang : in bit_vector (0 to 1); f, Az, en : in bit; ph_1, ph_2 : in bit ); -- integer_32 is declared elsewhere to be a bit_vector ( 0 to 31). -- Note that letting Z simply be type integer suggests that the -- synthesis tool should produce a bit_vector capable of -- displaying the full range of integers, i.e. 32 bits. This is, -- in fact, just what was wanted. end Z_Adder; architecture Concurrent of Z_Adder is signal A_in, B_in : integer; signal Z1_in, Z2_in : integer; signal Zsum, Zang_out : integer; signal GND, open_src : integer := 0; signal Zc, Zc_in : bit; -- again, we would synthesize 32 bit buses for everything -- declared "integer." begin -- transmission gates from Data Buses A_in <= Data_A when ph_1 = '1' else A_in; B_in <= Data_B when ph_1 = '1' else B_in; -- Leaving out the else clauses here would be more efficient from -- a simulation point of view, but it makes explicit what the -- synthesis tool has to generate i.e., a memoried element. In -- some tools this would lead to a redundant feedback from Q -- back to D. -- z2, z1, and Z_op are control signals from -- IKS controller selecting one of 9 functions -- to be implemented in the Z_adder. with z1 select Z1_in <= GND when "00", Data_P when "01", A_in when "10", open_src when "11"; with z2 select Z2_in <= GND when "00", B_in when "01", Zang_out when "10", open_src when "11"; with Z_op(0) select Zc_in <= Z_op(1) when '0', Az when '1'; -- All three WITH statements produce the multiplexors we want. -- Use of block to show design partition. -- These are the ph_2 enabled latches shown in the figure above. -- Note that synthesis tools like to have latches driven from a -- common enabling signal or clock in the same block. It makes -- for a cleaner model, too. Adder_blk: block signal ZA, ZB, Zout : integer; begin Zc <= Zc_in when ph_2 = '1' else Zc; ZA <= Z1_in when ph_2 = '1' else ZA; ZB <= Z2_in when ph_2 = '1' else ZB; -- Concurrent procedure call to CL_Adder, probably a high level -- model. Phase 1 enables latching the Zsum output. CL_Adder (Z1_in, Z2_in, Zout, Zc); Zsum <= Zout when ph_1='1' else Zsum; end block Adder_blk; -- Z is an output signal, but Zsum can be used -- internally. Z <= Zsum; -- Another concurrent procedure call. Complex -- function determining quadrant of angular -- computations. Compute_Angle ( Zsum, Zang_out, Zang, f, ph_1, s); -- Data_out is driving a bus that may be driven by other units. -- Guarded signal assignment is used here to provide tristate-like -- checking and driving of the bus. Tristate: block ((en = '1') and (ph_1='1')) begin Data_out <= guarded Zsum; end block Tristate; sign_Z <= transport '1' when zsum < 0 else '0'; end Concurrent;
Revised 1/29/98