-
Notifications
You must be signed in to change notification settings - Fork 0
Using Approxy
- Vivado within $PATH (recommended: Vivado v.2021.1)
- XSIM within $PATH
- Minimum Go 1.17
- Clone Approxy Repository:
git clone [email protected]:RickvanLoo/Approxy.git
- Optional: Checkout branch (v0.1.0 = MSc Version, v0.2.0 = Some changes, added documentation)
cd Approxy
git checkout v0.2.0
- Edit and save main.go
go build./Approxy
Recommended is for each Approxy Run to create a new function within either a new file or within main.go, i.e.
func WikiExample() {
// Here goes code
}For this example, an Approxy Run is created. This Run can be used to analyze multiple multipliers, for this example only one is being investigated.
func WikiExample() {
Run := Viv.StartRun(ReportPath, OutputPath, "WikiExample")
Run.ClearData()
}We are gonna analyze a 4-bit Recursive Multiplier using four 2-bit multipliers, twice M1 and twice M2. M1, M2, M3 and M4 are available globally.
These smaller multipliers are added into an size 4 array [4]VHDL.VHDLEntityMultiplier, the following indices explain which multiplier is used for which input bits
// LUTArray[0] = AH*BH
// LUTArray[1] = AH*BL
// LUTArray[2] = AL*BH
// LUTArray[3] = AL*BLFuthermore we generate testing data and the VHDL file in the OutputPath (Globally defined):
Rec1122 := VHDL.NewRecursive4("Rec1122", [4]VHDL.VHDLEntityMultiplier{M1, M1, M2, M2})
Rec1122.GenerateTestData(OutputPath)
Rec1122.GenerateVHDL(OutputPath)Optionally we can verify the generated VHDL file to the generated testing data. This is being done by XSIM. This verification can be important, given that the templates used for Approxy are not checked in any other way. If the verification fails, it means that the generated VHDL output file has different behavior than the generated testing data and requires debugging. The following code:
- Creates a XSIM object within Approxy for
Rec1122 - Sets the template to the default one for single multipliers
-
Exec()creates the testbench, and lets XSIM process this testbench - The XSIM report is being parsed, on fail Approxy does not continue executing
verify := Viv.CreateXSIM(OutputPath, "Verify", Rec1122.GenerateVHDLEntityArray())
verify.SetTemplateMultiplier()
verify.Exec()
err := Viv.ParseXSIMReport(OutputPath, Rec1122)
if err != nil {
log.Fatalln(err)
}One 4-bit multiplier will not produce any interesting results. Besides that it is questionable how accurate results are for analyzing such a small design, Vivado will simply produce a result of 0W for power estimations. The Scaler model can simply increase the amount of multipliers that will be independently implemented. This code will implement 1000 Rec1122 multipliers
Rec1122scaler := VHDL.New2DScaler(Rec1122, 1000)
Rec1122scaler.GenerateTestData(OutputPath)
Rec1122scaler.GenerateVHDL(OutputPath)The Vivado settings used for implementing the designs are global can be viewed and edited in the init() function in main.go
Code documentation explains what each setting does and can be verified with the Vivado commands in the 'vivado.tcl' template.
The following code, using default Approxy VivadoSettings, will synthesize, place and route Rec1122scaler for partname Xc7z030fbg676-3. Furthermore, various Vivado Checkpoints are written, 'funcsim' VHDL is written for post-PR analysis and timing and utilization reports are exported.
viv := Viv.CreateVivadoTCL(OutputPath, "main.tcl", Rec1122scaler, VivadoSettings)
viv.Exec()To be able to properly verify the power consumption of the design, a simulation has to be done using realistic input data, and a SAIF file needs to be exported.
This code creates a new XSIM environment for the scaled Rec1122scaler:
postanalysis := Viv.CreateXSIM(OutputPath, "postPR", Rec1122scaler.GenerateVHDLEntityArray())
postanalysis.SetTemplateScaler(1000) //Set Testbench template to Scaler for N=1000
postanalysis.CreateFile(true) //Create PostPR TestbenchNormal Distributed data is produced for 4-bit multipliers, and the XSIM simulation is executed which exports the SAIF file.
In function VHDL.NormalTestData the distribution can be viewed and modified.
Afterwards, a function call is made to the viv object, which opens the Vivado Checkpoint, loads the SAIF file and export a power report
VHDL.NormalTestData(Rec1122scaler, OutputPath, 1000) //Create i=1000 Normal Test Data for 4-bit
postanalysis.Funcsim()
viv.PowerPostPlacementGeneration() //Export PostPR dataThe last code creates an individual report for this multiplier configuration that has been verified, implemented and analyzed.
Note that this code creates the report for the scaled Rec1122scaler but we use information such as the MeanAbsoluteError for Uniform and Normal distribution just by using the functions from the multiplier Rec1122 itself. The Report is added to the Approxy Run.
Report := Viv.CreateReport(OutputPath, Rec1122scaler)
Report.AddData("MAE_Uniform", strconv.FormatFloat(Rec1122.MeanAbsoluteError(), 'E', -1, 64))
Report.AddData("MAE_Normal_1000", strconv.FormatFloat(Rec1122.MeanAbsoluteErrorNormalDist(1000), 'E', -1, 64))
Report.AddData("Overflow", strconv.FormatBool(Rec1122.Overflow()))
Run.AddReport(*Report)If a Run should be created that will analyze multiple configurations, a for or while loop can be used that iterates over multiple designs. As long as ALL EntityNames are unique, no conflicts should happen. To create the possibility to resume a Run without having to analyze multipliers that have already been added to the Run, the following piece of code can be used at the start of a loop. Note that it is currently not possible to resume an Approxy analysis that has not been finished yet. Stopping the execution of Approxy at any point before the Report is added to the Run, makes any generated data invalid.
if Run.Exists(Mult.EntityName) {
log.Printf(Yellow + "Warning, skipping Run: " + Mult.EntityName + "\n" + Reset)
continue
}Lets execute the full example by calling the newly created function in main() and show the results.
func main() {
WikiExample()
}func WikiExample() {
Run := Viv.StartRun(ReportPath, OutputPath, "WikiExample")
Run.ClearData()
Rec1122 := VHDL.NewRecursive4("Rec1122", [4]VHDL.VHDLEntityMultiplier{M1, M1, M2, M2})
Rec1122.GenerateTestData(OutputPath)
Rec1122.GenerateVHDL(OutputPath)
verify := Viv.CreateXSIM(OutputPath, "Verify", Rec1122.GenerateVHDLEntityArray())
verify.SetTemplateMultiplier()
verify.Exec()
err := Viv.ParseXSIMReport(OutputPath, Rec1122)
if err != nil {
log.Fatalln(err)
}
Rec1122scaler := VHDL.New2DScaler(Rec1122, 1000)
Rec1122scaler.GenerateTestData(OutputPath)
Rec1122scaler.GenerateVHDL(OutputPath)
viv := Viv.CreateVivadoTCL(OutputPath, "main.tcl", Rec1122scaler, VivadoSettings)
viv.Exec()
postanalysis := Viv.CreateXSIM(OutputPath, "postPR", Rec1122scaler.GenerateVHDLEntityArray())
postanalysis.SetTemplateScaler(1000) //Set Testbench template to Scaler for N=1000
postanalysis.CreateFile(true) //Create PostPR Testbench
VHDL.NormalTestData(Rec1122scaler, OutputPath, 1000) //Create i=1000 Normal Test Data for 4-bit
postanalysis.Funcsim()
viv.PowerPostPlacementGeneration() //Export PostPR data
Report := Viv.CreateReport(OutputPath, Rec1122scaler)
Report.AddData("MAE_Uniform", strconv.FormatFloat(Rec1122.MeanAbsoluteError(), 'E', -1, 64))
Report.AddData("MAE_Normal_1000", strconv.FormatFloat(Rec1122.MeanAbsoluteErrorNormalDist(1000), 'E', -1, 64))
Report.AddData("Overflow", strconv.FormatBool(Rec1122.Overflow()))
Run.AddReport(*Report)
}Build and Run:
go build
./Approxy
All Generated VHDL files, testdata, logs and reports can be monitored and viewed in the OutputPath, default: /output
The exported information in the Run can be viewed in the ReportPath, default: /report. For this example, the JSON file is found in /report/WikiExample.json
The Run containing a single Report is exported as the following JSON file:
{
"Name": "WikiExample",
"Reports": [
{
"EntityName": "Rec1122_scaler",
"Util": {
"TotalLUT": 23000,
"LogicLUT": 23000,
"LUTRAMs": 0,
"SRLs": 0,
"FFs": 0,
"RAMB36": 0,
"RAMB18": 0,
"DSP": 0,
"CARRY": 0
},
"Power": {
"TotalPower": 0.14,
"DynamicPower": 0.018,
"StaticPower": 0.121,
"ConfidenceLevel": "High"
},
"Timing": {
"EndPoint": "prod[0][3]",
"WorstPath": 1.461,
"MaxFreq": 684.4626967830252
},
"Other": [
{
"Key": "MAE_Uniform",
"Value": "3.4375E+00"
},
{
"Key": "MAE_Normal_1000",
"Value": "1.214E+00"
},
{
"Key": "Overflow",
"Value": "false"
}
]
}
],
"Other": null
}Recommended is to use a script, for instance in Python, to parse or plot the data.