VHDL arbiters - part II

This tutorial was designed using Quartus and Modelsim-Altera

In the previous installment, we defined what a HW arbiter is.
In this entry of the tutorial, we will see a simple implementation of a VHDL arbiter.

The arbiter of this example has three request inputs and three grant outputs.
Additionally, it has a 'busy' signal. Arbitration of the bus is done only while it is inactive. If the bus has already been granted to an agent, even if a bigger priority master requests the bus, the current transaction must complete before the arbiter gives grant signal to another master.

The logic for generating the grant signals (lines 41-43) is quite simple. If the first master (master 0) asserts a request, it is awarded grant. Master 1 is given grant only if it requests the bus and master 0 doesn't request the bus.
Master 2 is awarded grant only if it requests the bus and neither master 0 nor master 1 request the bus.

The gnt signal is changes only if the bus is not busy. The process and logic at lines 21 to 31 detects the falling edge of the busy signal. After busy goes low, all grant signals are de-asserted for one clock (line 39), and then the logic for choosing the next bus master is activated.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 entity arbiter is
   port (
     clk:  in std_logic;
     rst:  in std_logic;
  
     -- inputs
     req: in std_logic_vector(2 downto 0);
     busy:   in std_logic;
  
     -- outputs
     gnt: out std_logic_vector(2 downto 0)
   );
 end arbiter;


 architecture rtl of arbiter is
   signal busy_d : std_logic;
   signal busy_fe : std_logic;
  
 begin 
   busy_pr: process (clk, rst) 
   begin 
     if (rst = '1') then 
       busy_d <= '0';
     elsif (rising_edge(clk)) then
       busy_d <= busy;
     end if;
   end process busy_pr;

   -- Falling edge of busy signal
   busy_fe <= '1' when busy = '0' and busy_d = '1' else '0';

   arbiter_pr: process (clk, rst) 
   begin 
     if (rst = '1') then 
       gnt <= (others => '0');
     elsif (rising_edge(clk)) then
       if (busy_fe = '1') then
         gnt <= (others => '0');
       elsif (busy = '0') then     
         gnt(0) <= req(0);
         gnt(1) <= req(1) and not req(0);
         gnt(2) <= req(2) and not (req(0) or req(1));
       end if;  
     end if;
   end process arbiter_pr;

 end rtl;

The logic for gnt selection is a priority encoder where only one gnt bit is asserted for any combination of req signals. Let's see a Modelsim simulation of the thee-input arbiter:



Upon reset release, there are no outstanding requests so the arbiter also doesn't assert any grant
signals. Later on the simulation, several masters ask permission from the arbiter (request asserted) and are given grant according their priority.

Between 0.3 and 0.4us, master '1' asserts its request signal. Two clock cycles later, req from master '0' is asserted. So even if master '0' arrived later, when the arbiter is free to assign the bus, it will assign it to master '0'.

Notice that there is always a 'rest' clock between gnt signals. Each master uses the bus for four clocks, and relinquishes the bus (this can be seen in the duration of the busy signal).

Later on both master '2' and '0' request the bus and, as expected, the bus is granted to master '0'.

The VHDL source for the arbiter 'simple implementation', testbench and Modelsim files are available at Github





A generic form of the code for this kind of arbiter is:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 entity arbiter_gen is
   generic (
     ARBITER_W  : natural := 4
   );
   port (
     clk:  in std_logic;
     rst: in std_logic;
  
     -- inputs
     req: in std_logic_vector(ARBITER_W-1 downto 0);
     busy:      in std_logic;
  
     -- outputs
     gnt: out std_logic_vector(ARBITER_W-1 downto 0)
   );
 end arbiter_gen;
 
 architecture rtl of arbiter is
   signal busy_d : std_logic;
   signal busy_fe : std_logic;
  
 begin 
   busy_pr: process (clk, rst) 
   begin 
     if (rst = '1') then 
       busy_d <= '0';
     elsif (rising_edge(clk)) then
       busy_d <= busy;
     end if;
   end process busy_pr;

   -- Falling edge of busy signal
   busy_fe <= '1' when busy = '0' and busy_d = '1' else '0';

   arbiter_pr: process (clk, rst) 
   begin 
     if (rst = '1') then 
       gnt <= (others => '0');
     elsif (rising_edge(clk)) then
       if (busy_fe = '1') then
         gnt <= (others => '0');
       elsif (busy = '0') then     
         gnt(0) <= req(0);
         for I in 1 to ARBITER_W-1 loop
           prio_req := '0';
           for J in 1 to I loop
             prio_req := prio_req or req(J-1);
           end loop;
           gnt(I) <= req(I) and not prio_req;
         end loop;
       end if;  
     end if;
   end process arbiter_pr;

 end rtl;

where the parameter ARBITER_W is the quantity of signals processed by the arbiter.

RTL - Fixed priority two port arbiter

RTL - Fixed priority three port arbiter

RTL - Four port VHDL arbiter with fixed priority


The RTL representations show the growing combinatorial complexity needed to take care of an increasing number of ports, and were generated with Quartus Prime 15.1. Note that some blocks (like the output FFs) are not single but stacked primitive instantiations.

As was described, if several masters request the bus, the master with the lowest number is given grant (recall that only one master shall receive grant at any given time). This arbiter has a fixed priority. Although it could be possible to use such an arbiter for certain applications, the most common type of arbiters don't have fixed priority.

We will talk more about this in the next installment.

The VHDL code for the generic, fixed priority arbiter, is also available at GitHub.


Proposed exercises

  1. As explained, this simple arbiter has a fixed priority. If several masters assert their request signals, the lowest numbered master is given grant. Design a fixed priority master where the highest numbered master has the highest priority.
  2. In this arbiter, as long as a master requests a bus, the bus is granted to it. Add timeout logic. If one master asserts request for more than 10 clk periods, de-assert the grant signal to this master if other requests are outstanding.
  3. Some arbiters have a park feature. Park means that if there are no outstanding requests, the grant signal is given to the last master who received it. In another version, if no master asserts request, the gnt signal is assigned to a 'default master'. Design code for each one of those two options.
Read the first part of this article

Comments

Popular posts from this blog

Xilinx AXI Stream tutorial - Part 1

FPGA internal tri-state buses

Pseudo random number generator Tutorial