@@ -56,6 +56,14 @@ bool MeasurePinToPinDelay(
56
56
int voltage_mv,
57
57
float & delay);
58
58
59
+ bool MeasureLUTDelay (
60
+ Socket& sock,
61
+ hdevice hdev,
62
+ int nlut,
63
+ int ninput,
64
+ PTVCorner corner,
65
+ float & delay);
66
+
59
67
bool ProgramAndMeasureDelay (
60
68
Socket& sock,
61
69
hdevice hdev,
@@ -65,6 +73,13 @@ bool ProgramAndMeasureDelay(
65
73
int voltage_mv,
66
74
float & delay);
67
75
76
+ float GetRoundTripDelayWith2x (
77
+ int src,
78
+ int dst,
79
+ PTVCorner corner);
80
+
81
+ Greenpak4LUT* GetRealLUT (Greenpak4BitstreamEntity* lut);
82
+
68
83
// Voltages to test at
69
84
// For now, 3.3 +/- 150 mV
70
85
const int g_testVoltages[] = {3150 , 3300 , 3450 };
@@ -503,36 +518,165 @@ bool MeasureCrossConnectionDelay(
503
518
if (!ProgramAndMeasureDelay (sock, hdev, bitstream, src, dst, corner.GetVoltage (), delay))
504
519
return false ;
505
520
521
+ // Subtract PCB and I/O buffer delays
522
+ delay -= GetRoundTripDelayWith2x (src, dst, corner);
523
+
524
+ return true ;
525
+ }
526
+
527
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
528
+ // Helper for subtracting I/O pad and test fixture delays from a measurement
529
+
530
+ float GetRoundTripDelayWith2x (
531
+ int src,
532
+ int dst,
533
+ PTVCorner corner)
534
+ {
506
535
// Subtract the PCB trace delay at each end of the line
507
- delay - = g_devkitCal.pinDelays [src].m_rising ;
508
- delay - = g_devkitCal.pinDelays [dst].m_rising ;
536
+ float delay = g_devkitCal.pinDelays [src].m_rising ;
537
+ delay + = g_devkitCal.pinDelays [dst].m_rising ;
509
538
510
539
// Subtract the I/O buffer delay at each end of the line
511
540
// TODO: import calibration from the Greenpak4Device and/or reset it?
512
541
CombinatorialDelay d;
513
- srciob = g_calDevice.GetIOB (src);
542
+ auto srciob = g_calDevice.GetIOB (src);
514
543
srciob->SetSchmittTrigger (false );
515
544
if (!srciob->GetCombinatorialDelay (" IO" , " OUT" , corner, d))
516
545
return false ;
517
- delay - = d.m_rising ;
546
+ delay + = d.m_rising ;
518
547
519
- dstiob = g_calDevice.GetIOB (dst);
548
+ auto dstiob = g_calDevice.GetIOB (dst);
520
549
dstiob->SetDriveType (Greenpak4IOB::DRIVE_PUSHPULL);
521
550
dstiob->SetDriveStrength (Greenpak4IOB::DRIVE_2X);
522
551
if (!dstiob->GetCombinatorialDelay (" IN" , " IO" , corner, d))
523
552
return false ;
524
- delay - = d.m_rising ;
553
+ delay + = d.m_rising ;
525
554
526
- return true ;
555
+ return delay ;
527
556
}
528
557
529
558
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
530
559
// Characterize LUTs
531
560
532
- bool MeasureLutDelays (Socket& /* sock*/ , hdevice /* hdev*/ )
561
+ /* *
562
+ @brief Gets the actual LUT object out of an entity that either is, or contains, a LUT
563
+ */
564
+ Greenpak4LUT* GetRealLUT (Greenpak4BitstreamEntity* lut)
565
+ {
566
+ // First, just try casting.
567
+ auto reallut = dynamic_cast <Greenpak4LUT*>(lut);
568
+ if (reallut)
569
+ return reallut;
570
+
571
+ // It would be too easy if that just worked, though... what if it's a muxed cell?
572
+ auto pair = dynamic_cast <Greenpak4PairedEntity*>(lut);
573
+ if (pair)
574
+ {
575
+ reallut = dynamic_cast <Greenpak4LUT*>(pair->GetEntity (" GP_2LUT" ));
576
+ if (reallut)
577
+ return reallut;
578
+ }
579
+
580
+ // Something is wrong
581
+ return NULL ;
582
+ }
583
+
584
+ bool MeasureLUTDelays (Socket& sock, hdevice hdev)
533
585
{
534
586
LogNotice (" Measuring LUT delays...\n " );
535
587
LogIndenter li;
588
+
589
+ // Test conditions (TODO: pass this in from somewhere?)
590
+ int voltage = 3300 ;
591
+ PTVCorner corner (PTVCorner::SPEED_TYPICAL, 25 , voltage);
592
+
593
+ // Characterize each LUT
594
+ // Don't forget to only measure pins it actually has!
595
+ float delay;
596
+ for (unsigned int nlut = 0 ; nlut < g_calDevice.GetLUTCount (); nlut++)
597
+ {
598
+ auto baselut = g_calDevice.GetLUT (nlut);
599
+ auto lut = GetRealLUT (baselut);
600
+ for (unsigned int npin = 0 ; npin < lut->GetOrder (); npin ++)
601
+ {
602
+ if (!MeasureLUTDelay (sock, hdev, nlut, npin, corner, delay))
603
+ return false ;
604
+
605
+ // For now, the parent (in case of a muxed lut etc) stores all timing data
606
+ // TODO: does this make the most sense?
607
+ char portname[] = " IN0" ;
608
+ portname[2 ] += npin;
609
+ baselut->AddCombinatorialDelay (portname, " OUT" , corner, CombinatorialDelay (delay, -1 ));
610
+ }
611
+ }
612
+
536
613
return true ;
537
614
}
538
615
616
+ bool MeasureLUTDelay (
617
+ Socket& sock,
618
+ hdevice hdev,
619
+ int nlut,
620
+ int ninput,
621
+ PTVCorner corner,
622
+ float & delay)
623
+ {
624
+ delay = -1 ;
625
+
626
+ // Create the device object
627
+ Greenpak4Device device (part, unused_pull, unused_drive);
628
+ device.SetIOPrecharge (false );
629
+ device.SetDisableChargePump (false );
630
+ device.SetLDOBypass (false );
631
+ device.SetNVMRetryCount (1 );
632
+
633
+ // Look up the LUT
634
+ auto lut = GetRealLUT (device.GetLUT (nlut));
635
+
636
+ // See which half of the device it's in. Use pins 3/4 or 13/14 as appropriate
637
+ int src = 3 ;
638
+ int dst = 4 ;
639
+ if (lut->GetMatrix () == 1 )
640
+ {
641
+ src = 13 ;
642
+ dst = 14 ;
643
+ }
644
+
645
+ // Configure the input pin
646
+ auto vss = device.GetGround ();
647
+ auto srciob = device.GetIOB (src);
648
+ srciob->SetInput (" OE" , vss);
649
+ auto din = srciob->GetOutput (" OUT" );
650
+
651
+ // Configure the LUT
652
+ lut->MakeXOR ();
653
+ lut->SetInput (" IN0" , vss);
654
+ lut->SetInput (" IN1" , vss);
655
+ lut->SetInput (" IN2" , vss);
656
+ lut->SetInput (" IN3" , vss);
657
+ char portname[] = " IN0" ;
658
+ portname[2 ] += ninput;
659
+ lut->SetInput (portname, din);
660
+
661
+ // Configure the output pin
662
+ auto vdd = device.GetPower ();
663
+ auto dstiob = device.GetIOB (dst);
664
+ dstiob->SetInput (" IN" , lut->GetOutput (" OUT" ));
665
+ dstiob->SetInput (" OE" , vdd);
666
+ dstiob->SetDriveType (Greenpak4IOB::DRIVE_PUSHPULL);
667
+ dstiob->SetDriveStrength (Greenpak4IOB::DRIVE_2X);
668
+
669
+ // Generate a bitstream
670
+ vector<uint8_t > bitstream;
671
+ device.WriteToBuffer (bitstream, 0 , false );
672
+ // device.WriteToFile("/tmp/test.txt", 0, false); //for debug in case of failure
673
+
674
+ // Get the delay
675
+ if (!ProgramAndMeasureDelay (sock, hdev, bitstream, src, dst, corner.GetVoltage (), delay))
676
+ return false ;
677
+
678
+ // Subtract PCB trace and IO buffer delays
679
+ delay -= GetRoundTripDelayWith2x (src, dst, corner);
680
+
681
+ return true ;
682
+ }
0 commit comments