Parasitic interaction between oscillating LUTs on Silego GreenPAK 4
Tags:In a previous note I’ve discovered that a ring oscillator made from three nearby GP_LUT2
configured as inverters oscillates faster than a single GP_LUT2
, whereas the expected behavior is that it would three times slower. In this note I describe how that happens.
This is the logic that exhibits anomalous behavior:
1
2
3
4
5
6
7
8
9
10
11
12
module top(
(*LOC="P4"*) output q0,
(*LOC="P5"*) output q1,
(*LOC="P6"*) output q2
);
(* LOC="LUT2_0" *)
GP_2LUT #(.INIT(4'b0001)) lut1(.IN0(q0), .OUT(q1));
(* LOC="LUT2_1" *)
GP_2LUT #(.INIT(4'b0001)) lut2(.IN0(q1), .OUT(q2));
(* LOC="LUT2_2" *)
GP_2LUT #(.INIT(4'b0001)) lut3(.IN0(q2), .OUT(q0));
endmodule
The first thing I tried was to hook up the scope to the output of all three LUTs. Sure enough, they’re phase-matched perfectly:
In contrast, this is how it should look (and how it looks if I move lut3
to LUT2_4
, which is in another matrix):
Now, why does that happen? Let’s permute the logic to find out:
-
Swap the LUTs: phase-matched.
1 2 3 4 5 6 7 8 9 10 11 12
module top( (*LOC="P4"*) output q0, (*LOC="P5"*) output q1, (*LOC="P6"*) output q2 ); (* LOC="LUT2_2" *) GP_2LUT #(.INIT(4'b0001)) lut1(.IN0(q0), .OUT(q1)); (* LOC="LUT2_1" *) GP_2LUT #(.INIT(4'b0001)) lut2(.IN0(q1), .OUT(q2)); (* LOC="LUT2_0" *) GP_2LUT #(.INIT(4'b0001)) lut3(.IN0(q2), .OUT(q0)); endmodule
-
Introduce a gap instead of using consecutive LUTs: phase-matched.
1 2 3 4 5 6 7 8 9 10 11 12
module top( (*LOC="P4"*) output q0, (*LOC="P5"*) output q1, (*LOC="P6"*) output q2 ); (* LOC="LUT2_0" *) GP_2LUT #(.INIT(4'b0001)) lut1(.IN0(q0), .OUT(q1)); (* LOC="LUT2_1" *) GP_2LUT #(.INIT(4'b0001)) lut2(.IN0(q1), .OUT(q2)); (* LOC="LUT2_3" *) GP_2LUT #(.INIT(4'b0001)) lut3(.IN0(q2), .OUT(q0)); endmodule
-
Use three LUTs from another matrix: phase-matched.
1 2 3 4 5 6 7 8 9 10 11 12
module top( (*LOC="P4"*) output q0, (*LOC="P5"*) output q1, (*LOC="P6"*) output q2 ); (* LOC="LUT2_4" *) GP_2LUT #(.INIT(4'b0001)) lut1(.IN0(q0), .OUT(q1)); (* LOC="LUT2_5" *) GP_2LUT #(.INIT(4'b0001)) lut2(.IN0(q1), .OUT(q2)); (* LOC="LUT2_6" *) GP_2LUT #(.INIT(4'b0001)) lut3(.IN0(q2), .OUT(q0)); endmodule
-
Use only two LUTs in a ring: phase-matched—nevermind this circuit shouldn’t oscillate at all!
1 2 3 4 5 6 7 8 9
module top( (*LOC="P4"*) output q0, (*LOC="P5"*) output q1 ); (* LOC="LUT2_0" *) GP_2LUT #(.INIT(4'b0001)) lut1(.IN0(q0), .OUT(q1)); (* LOC="LUT2_1" *) GP_2LUT #(.INIT(4'b0001)) lut2(.IN0(q1), .OUT(q2)); endmodule
-
Use three completely independent oscillators: still phase-matched.
1 2 3 4 5 6 7 8 9 10 11 12
module top( (*LOC="P4"*) output q0, (*LOC="P5"*) output q1, (*LOC="P6"*) output q2 ); (* LOC="LUT2_0" *) GP_2LUT #(.INIT(4'b0001)) lut1(.IN0(q0), .OUT(q0)); (* LOC="LUT2_1" *) GP_2LUT #(.INIT(4'b0001)) lut2(.IN0(q1), .OUT(q1)); (* LOC="LUT2_2" *) GP_2LUT #(.INIT(4'b0001)) lut3(.IN0(q2), .OUT(q2)); endmodule
-
Move the third independent oscillator to the other matrix:
lut3
loses the phase relationship tolut1
andlut2
.1 2 3 4 5 6 7 8 9 10 11 12
module top( (*LOC="P4"*) output q0, (*LOC="P5"*) output q1, (*LOC="P6"*) output q2 ); (* LOC="LUT2_0" *) GP_2LUT #(.INIT(4'b0001)) lut1(.IN0(q0), .OUT(q0)); (* LOC="LUT2_1" *) GP_2LUT #(.INIT(4'b0001)) lut2(.IN0(q1), .OUT(q1)); (* LOC="LUT2_4" *) GP_2LUT #(.INIT(4'b0001)) lut3(.IN0(q2), .OUT(q2)); endmodule
It seems that the parasitic interactions between the LUTs that are physically adjacent to each other are very strong—in fact favored more than the actual function they’re supposed to implement.
Interestingly, in the case of three completely independent oscillators—but not any of the previous ones—there is even a second-order effect, with the output signals appearing modulated by another signal that is phase-shifted across the three oscillators: