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:

gp_2lut_x3.v
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 to lut1 and lut2.

    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:


Want to discuss this note? Drop me a letter.