Skip to content

Commit

Permalink
Update nix-eda, nl2bench (#52)
Browse files Browse the repository at this point in the history
* update nix-eda to `0814aa6c`
* update nl2bench to 0.5.0 -- new pyosys-based version
* add experimental support for podemquest
Co-authored-by: Youssef Kandil <[email protected]>
  • Loading branch information
donn authored Oct 23, 2024
1 parent 6500183 commit 0d6ab60
Show file tree
Hide file tree
Showing 15 changed files with 364 additions and 269 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ parsetab.py

.swiftpm/
abc.history
temp.txt
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.4
5.8
3 changes: 2 additions & 1 deletion Benchmarks/Benchmarks/aes128.v
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
* limitations under the License.
*/

module aes128(clk, state, key, out);
module aes128(clk, state, key, out, reset);
input clk;
input reset;
input [127:0] state, key;
output [127:0] out;
reg [127:0] s0, k0;
Expand Down
4 changes: 2 additions & 2 deletions Benchmarks/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function usage() {
echo " --all Runs Fault's complete flow"
echo " --synth Runs synthesis script"
echo " --cut Runs cut option on the synthesized netlist"
echo " -g, --tvgen Runs fault simulation using the specified TV generator (swift, atalanta, LFSR, PODEM)"
echo " -g, --tvgen Runs fault simulation using the specified TV generator (swift, atalanta, LFSR, PODEM, PodemQuest)"
echo " --delay Runs the transition fault simulator"
echo " --chain Runs chain option on the synthesized netlist"
echo " --tap Runs tap option on the chained netlist"
Expand Down Expand Up @@ -194,7 +194,7 @@ do
ignoring="-i $ignored_input,$clock_signal,$reset_signal"
fi
# Check tvgen type
if [ $tvgen = "atalanta" ] || [ $tvgen = "podem" ];
if [ $tvgen = "atalanta" ] || [ $tvgen = "podem" ] || [ $tvgen = "PodemQuest" ];
then
bench=$cut_netlist.bench
echo "Generating bench circuit for $cut_netlist"
Expand Down
185 changes: 108 additions & 77 deletions Sources/Fault/Entries/atpg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,97 +12,131 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import ArgumentParser
import BigInt
import Collections
import ArgumentParser
import CoreFoundation // Not automatically imported on Linux
import CoreFoundation // Not automatically imported on Linux
import Defile
import Foundation
import PythonKit
import Yams


extension Fault {
struct ATPG: ParsableCommand {
static let configuration = CommandConfiguration(
abstract: "Generate/import test vectors for a particular circuit and calculate coverage."
abstract:
"Generate/import test vectors for a particular circuit and calculate coverage."
)

@Option(
name: [.short, .long], help: "Path to the output JSON file. (Default: input + .tv.json)"
)

@Option(name: [.short, .long], help: "Path to the output JSON file. (Default: input + .tv.json)")
var output: String?

@Option(help: "Path to the output SVF file. (Default: input + .tv.svf)")
var outputSvf: String?

@Option(name: [.long, .customLong("output-faultPoints")], help: "Path to the output yml file listing all generated fault points. (Default: nil)")

@Option(
name: [.long, .customLong("output-faultPoints")],
help: "Path to the output yml file listing all generated fault points. (Default: nil)")
var outputFaultPoints: String?

@Option(name: [.long, .customLong("output-covered")], help: "Path to the output yml file listing coverage metadata, i.e., ratio and fault points covered. (Default: nil)")

@Option(
name: [.long, .customLong("output-covered")],
help:
"Path to the output yml file listing coverage metadata, i.e., ratio and fault points covered. (Default: nil)"
)
var outputCoverageMetadata: String?

@Option(name: [.short, .long, .customLong("cellModel")], help: "A Verilog model with which standard cells can be simulated.")

@Option(
name: [.short, .long, .customLong("cellModel")],
help: "A Verilog model with which standard cells can be simulated.")
var cellModel: String

@Option(name: [.customShort("v"), .long], help: "Number of test vectors to generate in the first batch.")

@Option(
name: [.customShort("v"), .long],
help: "Number of test vectors to generate in the first batch.")
var tvCount: Int = 100

@Option(name: [.customShort("r"), .long], help: "Increment in test vector count in subsequent batches should sufficient coverage not be reached.")

@Option(
name: [.customShort("r"), .long],
help:
"Increment in test vector count in subsequent batches should sufficient coverage not be reached."
)
var increment: Int = 50

@Option(name: [.short, .long], help: "The minimum coverage to reach before ceasing increments. If set to 0, only the initial batch is run.")

@Option(
name: [.short, .long],
help:
"The minimum coverage to reach before ceasing increments. If set to 0, only the initial batch is run."
)
var minCoverage: Float = 80

@Option(help: "Ceiling for Test Vector increments: if this number is reached, no more increments will occur regardless the coverage.")

@Option(
help:
"Ceiling for Test Vector increments: if this number is reached, no more increments will occur regardless the coverage."
)
var ceiling: Int?

@Option(help: "Type of the pseudo-random internal test-vector-generator.")
var tvGen: String = "swift"

@Option(help: "A \(MemoryLayout<UInt>.size)-byte value to use as an RNG seed for test vector generators, provided as a hexadecimal string (without 0x).")

@Option(
help:
"A \(MemoryLayout<UInt>.size)-byte value to use as an RNG seed for test vector generators, provided as a hexadecimal string (without 0x)."
)
var rngSeed: String = "DEADCAFEDEADF00D"

@Option(name: [.customShort("g"), .long], help: "Use an external TV Generator: Atalanta or PODEM.")

@Option(
name: [.customShort("g"), .long],
help: "Use an external TV Generator: Atalanta or PODEM.")
var etvGen: String?

@Option(name: [.short, .long], help: "Netlist in bench format. (Required iff generator is set to Atalanta or PODEM.)")

@Option(
name: [.short, .long],
help: "Netlist in bench format. (Required iff generator is set to Atalanta or PODEM.)")
var bench: String?

@Flag(help: "Generate only one testbench for inspection, and do not delete it.")
var sampleRun: Bool = false

@OptionGroup
var bypass: BypassOptions
@Option(help: "If provided, this JSON file's test vectors are simulated and no generation is attempted.")
var externalTVSet: String?

@Option(help: "If provided, this JSON file's test vector are used as the initial set of test vectors, with iterations taking place with them in mind.")

@Option(
help:
"If provided, this JSON file's test vector are used as the initial set of test vectors, with iterations taking place with them in mind."
)
var iteratingUpon: String?

@Option(name: [.customShort("D"), .customLong("define")], help: "Define statements to include during simulations.")

@Option(
name: [.customShort("D"), .customLong("define")],
help: "Define statements to include during simulations.")
var defines: [String] = []

@Option(name: [.customShort("I"), .customLong("include")], help: "Extra verilog models to include during simulations.")

@Option(
name: [.customShort("I"), .customLong("include")],
help: "Extra verilog models to include during simulations.")
var includes: [String] = []

@Argument(help: "The cutaway netlist to generate patterns for.")
var file: String

mutating func run() throws {

if !TVGeneratorFactory.validNames.contains(tvGen) {
throw ValidationError("Invalid test-vector generator \(tvGen).")
}

let fileManager = FileManager()
guard fileManager.fileExists(atPath: file) else {
throw ValidationError("File '\(file)' not found.")
}

guard fileManager.fileExists(atPath: cellModel) else {
throw ValidationError("Cell model file '\(cellModel)' not found.")
}

if !cellModel.hasSuffix(".v"), !cellModel.hasSuffix(".sv") {
Stderr.print(
"Warning: Cell model file provided does not end with .v or .sv."
Expand All @@ -111,7 +145,7 @@ extension Fault {

let jsonOutput = output ?? file.replacingExtension(".cut.v", with: ".tv.json")
let svfOutput = outputSvf ?? file.replacingExtension(".cut.v", with: ".tv.svf")

// MARK: Importing Python and Pyverilog

let parse = Python.import("pyverilog.vparser.parser").parse
Expand Down Expand Up @@ -143,46 +177,36 @@ extension Fault {
var etvSetVectors: [TestVector] = []
var etvSetInputs: [Port] = []

if let tvSetTest = externalTVSet {
if !fileManager.fileExists(atPath: tvSetTest) {
throw ValidationError("TVs JSON file '\(tvSetTest)' not found.")
}
if tvSetTest.hasSuffix(".json") {
(etvSetVectors, etvSetInputs) = try TVSet.readFromJson(file: tvSetTest)
} else {
(etvSetVectors, etvSetInputs) = try TVSet.readFromText(file: tvSetTest)
}
print("Read \(etvSetVectors.count) externally-generated vectors to verify.")
}

if let tvGenerator = etvGen {
guard let etvgen = ETVGFactory.get(name: tvGenerator) else {
Stderr.print("Unknown external test vector generator '\(tvGenerator)'.")
Foundation.exit(EX_USAGE)
}
let benchUnwrapped = bench! // Program exits if etvGen.value isn't nil and bench.value is or vice versa

let benchUnwrapped = bench! // Program exits if etvGen.value isn't nil and bench.value is or vice versa

if !fileManager.fileExists(atPath: benchUnwrapped) {
throw ValidationError("Bench file '\(benchUnwrapped)' not found.")
}
(etvSetVectors, etvSetInputs) = etvgen.generate(file: benchUnwrapped, module: "\(definition.name)")
(etvSetVectors, etvSetInputs) = etvgen.generate(
file: benchUnwrapped, module: "\(definition.name)")

if etvSetVectors.count == 0 {
Stderr.print("Bench netlist appears invalid (no vectors generated). Are you sure there are no floating nets/outputs?")
Stderr.print(
"Bench netlist appears invalid (no vectors generated). Are you sure there are no floating nets/outputs?"
)
Foundation.exit(EX_DATAERR)
} else {
print("Generated \(etvSetVectors.count) test vectors using external utilties to verify.")
print(
"Generated \(etvSetVectors.count) test vectors using external utilties to verify."
)
}
}

let tvMinimumCoverage = minCoverage / 100
let finalTvCeiling: Int = ceiling ?? (
etvSetVectors.count == 0 ?
1000 :
etvSetVectors.count
)

let finalTvCeiling: Int =
ceiling ?? (etvSetVectors.count == 0 ? 1000 : etvSetVectors.count)

let finalRNGSeed = UInt(rngSeed, radix: 16)!

do {
Expand Down Expand Up @@ -217,7 +241,7 @@ extension Fault {
evtInputsMinusIgnored.append(input)
}
}
assert(inputsMinusIgnored.count == evtInputsMinusIgnored.count);
assert(inputsMinusIgnored.count == evtInputsMinusIgnored.count)
inputsMinusIgnored = evtInputsMinusIgnored
}

Expand All @@ -230,7 +254,7 @@ extension Fault {
} else {
let minimum = min(port.from, port.to)
let maximum = max(port.from, port.to)
for i in minimum ... maximum {
for i in minimum...maximum {
faultPoints.insert("\(port.name) [\(i)]")
}
}
Expand All @@ -255,10 +279,14 @@ extension Fault {
}

if warnAboutDFF {
print("Warning: D-flipflops were found in this netlist. Are you sure you ran it through 'fault cut'?")
print(
"Warning: D-flipflops were found in this netlist. Are you sure you ran it through 'fault cut'?"
)
}

print("Found \(faultPoints.count) fault sites in \(gateCount) gates and \(ports.count) ports.")
print(
"Found \(faultPoints.count) fault sites in \(gateCount) gates and \(ports.count) ports."
)

// MARK: Load Initial Set

Expand Down Expand Up @@ -314,16 +342,18 @@ extension Fault {
coverageList: result.coverageList
)
let jsonRawOutput = jsonOutput.replacingExtension(".tv.json", with: ".raw_tv.json")

print("Writing raw generated test vectors in Fault JSON format to \(jsonOutput)")
try encoder.encode(rawTVInfo).write(to: URL(fileURLWithPath: jsonRawOutput))

let tvInfo = TVInfo(
inputs: inputsMinusIgnored,
outputs: outputs,
coverageList: Compactor.compact(coverageList: result.coverageList)
)
print("Writing compacted generated test vectors in Fault JSON format to \(jsonOutput)")
print(
"Writing compacted generated test vectors in Fault JSON format to \(jsonOutput)"
)
try encoder.encode(tvInfo).write(to: URL(fileURLWithPath: jsonOutput))

// try File.open(svfOutput, mode: .write) {
Expand All @@ -332,7 +362,8 @@ extension Fault {
// }

if let coverageMetaFilePath = outputCoverageMetadata {
print("Writing YAML file of final coverage metadata to \(coverageMetaFilePath)")
print(
"Writing YAML file of final coverage metadata to \(coverageMetaFilePath)")
try File.open(coverageMetaFilePath, mode: .write) {
try $0.write(string: YAMLEncoder().encode(result.coverageMeta))
}
Expand Down
Loading

0 comments on commit 0d6ab60

Please sign in to comment.