Arbiter

In this next example, we will demonstrate a more interesting use of if statements. We will also see the pattern for resetting a register.

Arbiter is a circuit which allows two clients to ask for access to a device, but only grants access to one of them at a time.

arbiter.vir
mod Arbiter {
    incoming clock   : Clock
    incoming reset   : Reset

    incoming req0   : Bit // client 0 is requesting access
    incoming req1   : Bit // client 1 is requesting access

    outgoing grant0 : Bit // client 0 is granted access
    outgoing grant1 : Bit // client 1 is granted access

    // When true, client 0 has priority
    reg priority_for_client_0 : Bit on clock

    // while resetting, neither client gets the grant
    if reset {
        priority_for_client_0 <= true

        grant0 := false
        grant1 := false
    } else {
        // each cycle alternate between
        // giving priority to client 0
        // and giving it to client 1
        priority_for_client_0 <= !priority_for_client_0

        if priority_for_client_0 {
            grant0 := req0
            grant1 := req1 && !req0
        } else {
            grant0 := req0 && !req1
            grant1 := req1
        }
    }
}

What it Does

In hardware designs, it’s very common to share a hardware device between multiple clients. If the device can only handle on transaction at a time, we need an arbiter to decide which client gets to use it.

When the first client wants access, it asserts client0. Similarly, when the second client wants access, it asserts client1.

The Arbiter asserts grant0 to grant access to the first client, and it asserts grant1 to grant access to the second. But Arbiter never asserts both at the same time.

Clock and Reset

Most modules you will write will have both a clock and a reset like this:

incoming clock   : Clock
incoming reset   : Reset

The type of reset signals is Reset. You should pretty much always name your reset signal reset.

Priority

An important piece of how Arbiter works is this register:

// When true, client 0 has priority
reg priority_for_client_0 : Bit on clock

Imagine if both clients make a request on the same cycle. What happens?

When priority_for_client_0 is asserted, then client 0 has priority. This means, in the event of a tie, if priority_for_client_0 is true, then client 0 wins. Otherwise, if priority_for_client_0 is false and the tie goes to client 1.

Nested If Statements

The heart of Arbiter is this big block of code:

// while resetting, neither client gets the grant
if reset {
    priority_for_client_0 <= true

    grant0 := false
    grant1 := false
} else {
    // each cycle alternate between
    // giving priority to client 0
    // and giving it to client 1
    priority_for_client_0 <= !priority_for_client_0

    if priority_for_client_0 {
        grant0 := req0
        grant1 := req1 && !req0
    } else {
        grant0 := req0 && !req1
        grant1 := req1
    }
}

We see at the top that this is an if statement. We are asking, “Is the circuit currently being reset?”

If we are resetting the circuit, we see that priority_for_client_0 will latch true on the next cycle. On the current cycle, both clients are denied access.

What happens after a reset?

Round Robin

This line looks a little funny:

// each cycle alternate between
// giving priority to client 0
// and giving it to client 1
priority_for_client_0 <= !priority_for_client_0

The ! operator is logical NOT. This driver has the effect of flipping priority_for_client_0 from true to false or from false to true each cycle.

Note

Because we are using <= here and not :=, we are allowed to use priority_for_client_0 on both the left hand side and the right hand side of the same driver.

This works because <= means we are taking the value of the right hand side on this cycle and we will be making it the value of the left hand side for the next cycle.

Granting Access

The remaining lines give the logic for actually granting access.

if priority_for_client_0 {
    grant0 := req0
    grant1 := req1 && !req0
} else {
    grant0 := req0 && !req1
    grant1 := req1
}

The client with priority will get it simply by asking for it. The other client will get it only if it both asks and if the other doesn’t.

The logic is symmetric. It’s quite pleasing, isn’t it?