Defining the LUT Routing

The previous section showed how to enforce the placement of design components. With the described methods, it is possible to specify in which logic elements (LEs) the single components are implemented. But there is no immediate way to specify which of the four LUT inputs of an LCELL is used for which input signal. Leaving this up to the compiler may also lead to inferior uniqueness as outlined in the following.

Consider the simple example of an LUT that only passes on its one input signal to its output—atypical application in delay-based PUFs on FPGAs. To use LUT input A, the LUT mask is set to 1010101010101010 = AAAA (cf.Fig.11.3); for LUT input B №1100110011001100 = CCCC; for LUT input C to 1111000011110000 = F0F0; and for LUT input D to 1111111100000000 = FF00. All of these configurations logically perform the same task. A glance at Fig. 11.3, however, reveals that the path from input A to the output is the longest of all the inputs, whereas the path from input D to the output is the shortest. In the real FPGA hardware it might not necessarily be the case that the delay of input D to the output is indeed the fastest. This depends on how the hardware is really structured. But there are definitely significant delay differences between the different LUT inputs.

For the implementation of a delay-based PUF, such differences can have a severe impact on the PUF quality. If, for example the LCELLs of one RO x mainly use their LUT input A and the LCELLs of another RO y mainly use their input D, RO x will most likely be slower than RO y on all FPGAs; leading to poor uniqueness. Such scenarios do in fact occur, if the LUT routing is left to the compiler. This section does therefore presents how to enforce the LUT routing as well.

To manually change the used LUT inputs, one has to open the Quartus Resource Property Editor by double-clicking on an LE in the Chip Planner. There, the “Signal Name” of each LUT input can be edited or removed. To change, e.g. a LUT using input C to using input D, copy the signal name for input C and paste it for input D. Then remove the connection for input C. Lastly, change the LUT mask from F0F0 to FF00. Afterwards, the corresponding changes are listed in the Chip Planner’s “Change Manager”, and can be applied by clicking the “Check and Save All Netlist Changes” button.

Instead of applying all changes manually, which is rather tedious and error-prone for larger amounts of LUTs, it is advisable to write a script to perform them automatically. With a right-click in the “Change Manager”, any changes can be exported to a TCL file (e.g. changes.tcl) that performs the changes when called with the console command:

quartus_cdb -t changes.tcl

Thus, applying the above three example changes to, e.g. LCELL 3 of RO 0 can be performed by the TCL script given in Listing 11.5. The actual changes are defined in Lines 19-21 (add the connection to LUT input D), Lines 43-44 (remove the connection of LUT input C), and Lines 63-65 (change the LUT mask). But the preceding set node_properties commands (Lines 9-18, 30-42, 53-62) are necessary, too. Here, the state of the LCELL prior to the change has to be given. Notice that the “fanins” for the first change (Lines 13-17) only include the one connection to LUT input C coming from the previous LCELL 2 (lc_gen:2). After adding the connection to LUT input D, the “fanins” of the next change must also include that connection (Lines 34-41). After removing the connection to LUT input C, the “fanins” of the third change is only left with the connection to LUT input D (Lines 58-60). Apart from the “fanins”, the current LUT mask has to be stated in each set node_properties command (Lines 12, 33, 56). Would there be more changes to this LCELL in this TCL script, the new LUT mask FF00 would have to be stated for all subsequent changes.

Listing 11.5 changes.tcl_

  • 1 package require ::quartus::chip_planner
  • 2 package require ::quartus::project
  • 3 load_chip_planner_utility_commands
  • 4 project_open myPUF -revision myPUF
  • 5 read_netlist
  • 6 set had_failure 0
  • 7
  • 8 # Adding LUT input D of LCELL 3 of RO 0.
  • 9 set node_properties [ node_properties_record #auto

10 -node_name |myPUF | ros:ros | ro: o_gen:0:ro_i | lc_gen:3:lc_i

  • 11 -node_type LCCOMB_CII -op_mode normal -data_to_lut_c "Data C"
  • 12 -sum_lut_mask F0F0
  • 13 -fanins [ list
  • 14 [ fanin_record #auto -dst {-port_type DATAC -lit_index 0}

15 -src { -node_name |myPUF | ros:ros |ro: o_gen:0:ro_i |lc_gen:2:lc_i

  • 16 -port_type COMBOUT -lit_index 0} -delay_chain_setting -1 ]
  • 17 ]
  • 18 ]
  • 19 set result [ make_ape_connection_wrapper

20 node iperties |myPUF|ros:ros|ro: o_gen:0:ro_i |lc_gen:3:lc_i DATAD 0

21 |myPUF|ros:ros|ro: o_gen:0:ro_i|lc_gen:2:lc_i COMBOUT 0 -1 ]

  • 22 if { $result == 0 } {
  • 23 set had_failure 1
  • 24 puts "Use the following information to evaluate how to apply this change."
  • 25 dump_node $node_properties
  • 26 }
  • 27 remove_all_record_instances
  • 28
  • 29 # Removing LUT input C of LCELL 3 of RO 0.
  • 30 set node_properties [ node_properties_record #auto

31 -node_name |myPUF|ros:ros|ro: o_gen:0:ro_i |lc_gen:3:lc_i

  • 32 -node_type LCCOMB_CII -op_mode normal -data_to_lut_c "Data C"
  • 33 -sum_lut_mask F0F0
  • 34 -fanins [ list
  • 35 [ fanin_record #auto -dst {-port_type DATAC -lit_index 0}

36 -src { -node_name |myPUF | ros:ros |ro: o_gen:0:ro_i |lc_gen:2:lc_i

  • 37 -port_type COMBOUT _index 0} -delay_chain_setting -1 ]
  • 38 [ fanin_record #auto -dst {-port_type DATAD -lit_index 0}

39 -src { -node_name |myPUF | ros:ros |ro: o_gen:0:ro_i |lc_gen:2:lc_i

  • 40 -port_type COMBOUT _index 0} -delay_chain_setting -1 ]
  • 41 ]
  • 42 ]
  • 43 set result [ remove_ape_connection_wrapper

44 $node_properties |myPUF|ros:ros|ro: o_gen:0:ro_i |lc_gen:3:lc_i DATAC 0 ]

  • 45 if { $result == 0 } {
  • 46 set had_failure 1
  • 47 puts "Use the following information to evaluate how to apply this change."
  • 48 dump_node $node_properties
  • 49 }
  • 50 remove_all_record_instances
  • 51
  • 52 # Changing LUT Mask of LCELL 3 of RO 0.
  • 53 set node_properties [ node_properties_record #auto

54 -node_name |myPUF|ros:ros|ro: o_gen:0:ro_i |lc_gen:3:lc_i

  • 55 -node_type LCCOMB_CII -op_mode normal -data_to_lut_c "Data C"
  • 56 -sum_lut_mask F0F0
  • 57 -fanins [ list
  • 58 [ fanin_record #auto -dst {-port_type DATAD -lit_index 0}

59 -src { -node_name |myPUF | ros:ros |ro: o_gen:0:ro_i |lc_gen:2:lc_i

  • 60 -port_type COMBOUT _index 0} -delay_chain_setting -1 ]
  • 61 ]
  • 62 ]
  • 63 set result [ set_lutmask_wrapper

64 $node_properties |myPUF|ros:ros|ro: o_gen:0:ro_i |lc_gen:3:lc_i

  • 65 "Sum LUT Mask" FF00 ]
  • 66 if { $result == 0 } {
  • 67 set had_failure 1
  • 68 puts "Use the following information to evaluate how to apply this change."
  • 69 dump_node $node_properties
  • 70 }
  • 71 remove_all_record_instances
  • 72
  • 73 # Apply the changes.
  • 74 set drc_result [check_netlist_and_save]
  • 75 if { $drc_result == 1 } {
  • 76 puts "check_netlist_and_save: SUCCESS"
  • 77 } else {
  • 78 puts "check_netlist_and_save: FAIL"
  • 79 }
  • 80 if { $had_failure == 1 } {
  • 81 puts "Not all set operations were successful"
  • 82 }
  • 83 project_close

1 ...

2 signal_name = ros:ros|ro: o_gen:0:ro_i|lc_gen:2:lc_i {

3 LOCAL_LINE:X34Y33S0I2;

4 dest = ( ros:ros|ro: o_gen:0:ro_i|lc_gen:3:lc_i, DATAA ), route_port = DATAC;

5 }

6 signal_name = ros:ros|ro: o_gen:0:ro_i|lc_gen:3:lc_i {

7 LOCAL_LINE:X34Y33S0I3;

8 dest = ( ros:ros|ro: o_gen:0:ro_i|lc_gen:4:lc_i, DATAA ), route_port = DATAD;

9 }

10 signal_name = ros:ros|ro: o_gen:0:ro_i|lc_gen:4:lc_i {

11 LOCAL_LINE:X34Y33S0I4;

12 dest = ( ros:ros|ro: o_gen:0:ro_i|lc_gen:5:lc_i, DATAA ), route_port = DATAC;

  • 13 }
  • 14 ...

Thus, a script generating the TCL file must—for each change—take into account all previous changes made to the respective LCELL, which raises the question how the initial states of all LCELLs can be known. As the compiler may chose the LUT inputs arbitrarily, there is no way to predict the routing. Instead, it has to be extracted after the compilation using the “Back-Annotate Assignments” feature already applied in Method 2 of Sect. 11.3.2. Only here, “Assignments” ^ “Back-Annotate Assignments” ^ “Pin, cell, routing & device assignments” is selected, as opposed to just “Pin, cell & device assignments”. This results in the generation of the Routing Constraints File myPUF.rcf in the project’s main directory. Within this file there are— albeit not in this correct order—entries of the following form:

To extract which LUT inputs are used for which LCELL, one has to look at the dest entry of the signal connected to that input. Thus, Lines 2-4 indicate that the output of LCELL 2 is connected to LUT input C (DATAC) of LCELL 3; just as Lines 6-8 indicate that the output of LCELL 3 is connected to LUT input D (DATAD) of LCELL 4. The LUT masks are not explicitly stated in the Routing Constraints File, but knowing the LUT inputs allows for them to be inferred.

The complete workflow for defining the LUT routing is hence:

  • 1. Compile the Quartus project enforcing the desired LUT placement as explained in Sect. 11.3.2.
  • 2. Use the “Back-Annotate Assignments” feature to generate the Routing Constraints File (.rcf).
  • 3. Check the .rcf file to extract original LUT inputs used by the compiler.
  • 4. Create a TCL script changes.tcl to change the LUT inputs as desired.
  • 5. Run quartus_cdb -t changes.tcl to execute the TCL script and apply the changes.
 
Source
< Prev   CONTENTS   Source   Next >