bob wrote:
In a bitboard design like this, you wouldn't have bitscans or movelists, but rather just move sets, i.e. attack bitboards. The MVV/LVA phase is basically this:
Code: Select all
for (enemy piece from queen to pawn)
{
for (friendly piece from pawn to king)
if (friendly piece attacks enemy piece)
generate capture;
}
...with those loops of course unrolled in the hardware. Very parallel.
You did catch my mention of "synchronous"? Which means each operation has to finish in a fixed amount of time. Loops don't happen. If you look at the belle design, the activities for a single node are fixed in length, each and every time. There is a loop to take one move at a time, but the loop is unlike anything we do in normal chess engines. It can't even search the hash move or killer move first, in fact. Because it doesn't have hash or killer moves and it doesn't generate moves like we do. That was the point here.
Yes, when I say that the loops are unrolled, I mean completely unrolled, with no breaking. That is, it tests all victims/attackers in parallel. Then there would be a similar priority mechanism, which would also extract the first bit of the victim and attacker bitboards (with the x&x-1 trick).
I suppose it would look something like this:
Code: Select all
Make victim bitboards by &ing each opp. piece with all of our attacks
Find highest attacked piece out of 5, extract the first bit (to)
Get attacker bitboards by anding all piece bitboards with the victim bit
Find lowest attacking piece out of 6, extract the first bit (from)
Extract victim's bit from attacker's attack set, to make sure we generate a different move next cycle
So 11 ands, two priority encoders, two LSB isolations, and then an xor to get rid of the move.
SEE is inherently non-synchronous since there are a variable number of pieces that can bear on a square, requiring loops which we do not want, since we always have to do the max number of loops to calculate the cycle time of the FSM.
I just said a simple SEE approximation. You can find whether victim pieces are defended/undefended, and if the attacker is more valuable than the victim, we can assume it's a bad capture and save it until the end. And by "saving" I mean we make two simultaneous passes over the MVV/LVA logic, one with "safe" captures, one without, and we only take the bad capture if there's no good ones. Not quite as good as real SEE, but certainly better than MVV/LVA.