Edit: as someone pointed out, I initially only pointed out how to set the input signals and gave two special cases as an example. Let me try to explain how it works. A good start for this is your question:
why ~(double_req-base) ?
As someone pointed out to you, this is based on the principle of the ripple borrow subtractor. When you subtract one number from another, regardless of the numeral system you are using, you start from the lowest order and try to subtract two numbers from the same order. In a binary example, this would look like this:
1011 = 11
0010 - = 2 -
────── ────
1001 = 9
As you can see, 1 - 1
is valid and yields 0
. However, if that's not possible you can borrow from a higher order number. This image shows a simple example of how this looks like in the decimal system. An example in the decimal system could be:
1001 = 01(10)1 = 9
0010 - = 00 1 0 - = 2 -
────── ───────── ───
0111 = 01 1 1 = 7
Since 0 - 1
is not possible in the second position, we take the 1 from the fourth position, set the third position to 1
and set the second postition to 10
(so, 2 in the decimal system). This is very similar to the example in the decimal system I posted before.
Important for the arbiter: the next 1 of the original number (req
), seen from the position of base
, will be set to zero. All numbers between the base position and that 0
will be set to 1
. After inverting the result of the subtraction, only this position will be 1
as seen from the base.
However, numbers with a lower order than the base could still be 1
with this technique. Therfore, we conjunct the original number with your calculated number (double_req & ~(double_req-base)
). This makes sure that possible 1
s at positions lower than base
are eliminated.
Finally, the fact that it is doubled up makes sure that it will not run out of positions to borrow from. If it needs to borrow from these "second" doubled up block, the disjunction (double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH]
) makes sure that it returns the right index. I added an example for this to the examples below.
Original post
You can interpret base
as your starting index in req
. This is the first bit the code will consider to arbitrate. You should set this value to last_arbitrated_position + 1
.
Take a look at the 4 bit (pseudocode) example I created below. Let's take some arbitrary numbers:
req = 4'b1101 // Your vector from which one position should be arbitrated
base = 4'b0010 // The second position is the first position to consider
Now, from arbiter.v
, the following follows:
double_req = 1101 1101
double_grant = 1101 1101 & ~(1101 1011) = 1101 1101 & 0010 0100 = 0000 0100
In the last steps, arbiter.v
then actually assigns the position that should be granted:
grant = 0100 | 0000 = 0100
This is correct, because we set the second position as base, and the next valid position was the third. Another example, where the base is a position which is also valid in req
, is:
req = 4'b1111
base = 4'b0010
double_req = 1111 1111
double_grant = 1111 1111 & ~(1111 1101) = 1111 1111 & 0000 0010 = 0000 0010
grant = 0010 | 0000
Which is again correct, because in this case we defined that the first position that may be arbitrated is the second position, and this position is indeed valid.
The code example you posted also takes care of wrapping around the most-significant bit. This means that if you set a base, but there is no valid position greater than that base, it will wrap around and start arbitration from the least-significant bit. An example for this case would be:
req = 4'b0010
base = 4'b0100
double_req = 0010 0010
double_grant = 0010 0010 & ~(1110 0001) = 0010 0010 & 0001 1110 = 0010 0000
grant = 0000 | 0010