Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update nix-eda, nl2bench #52

Merged
merged 8 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading