Skip to content

Commit

Permalink
Initial work on integrating quaigh
Browse files Browse the repository at this point in the history
  • Loading branch information
donn committed Jul 15, 2024
1 parent ac2cc21 commit 3182267
Show file tree
Hide file tree
Showing 27 changed files with 591 additions and 700 deletions.
10 changes: 3 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "Fault",
platforms: [
.macOS(.v11), // executableURL and a bunch of other things are not available before High Sierra
.macOS(.v13), // executableURL and a bunch of other things are not available before High Sierra
],
dependencies: [
// Dependencies declare other packages that this package depends on.
Expand All @@ -21,13 +21,9 @@ let package = Package(
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.executableTarget(
name: "Fault",
name: "fault",
dependencies: ["PythonKit", .product(name: "ArgumentParser", package: "swift-argument-parser"), "Defile", .product(name: "Collections", package: "swift-collections"), "BigInt", "Yams"],
path: "Sources"
),
.testTarget(
name: "FaultTests",
dependencies: ["Fault"]
),
)
]
)
2 changes: 1 addition & 1 deletion Sources/Fault/Compaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ enum Compactor {
if sa0 == sa0Final, sa1 == sa1Final {
let ratio = (1 - (Float(filtered.count) / Float(tvCount))) * 100
print("Initial TV Count: \(tvCount). Compacted TV Count: \(filtered.count). ")
print("Compaction is successfuly concluded with a reduction percentage of : \(String(format: "%.2f", ratio))% .\n")
print("Successfully compacted test vectors by a ratio of \(String(format: "%.2f", ratio))%.")
} else {
print("Error: All faults aren't covered after compaction .\n")
}
Expand Down
10 changes: 5 additions & 5 deletions Sources/Fault/Entries/asm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ extension Fault {
abstract: "Assemble test vectors and golden outputs from JSON and Verilog files."
)

@Option(name: [.customShort("o"), .long], help: "Path to the output vector file. (Default: <json input> + .vec.bin)")
@Option(name: [.customShort("o"), .long], help: "Path to the output vector file.")
var output: String?

@Option(name: [.customShort("O"), .long], help: "Path to the golden output file. (Default: <json input> + .out.bin)")
@Option(name: [.customShort("O"), .long], help: "Path to the golden output file.")
var goldenOutput: String?

@Argument(help: "JSON file (.json).")
Expand All @@ -47,8 +47,8 @@ extension Fault {
throw ValidationError("JSON file '\(json)' not found.")
}

let vectorOutput = output ?? "\(json).vec.bin"
let goldenOutput = goldenOutput ?? "\(json).out.bin"
let vectorOutput = output ?? json.replacingExtension(".json", with: ".bin")
let goldenOutput = goldenOutput ?? json.replacingExtension(".tv.json", with: ".au.bin")

print("Loading JSON data…")
let start = DispatchTime.now()
Expand Down Expand Up @@ -93,7 +93,7 @@ extension Fault {

for (i, output) in jsOutputOrder.enumerated() {
var name = output.name.hasPrefix("\\") ? String(output.name.dropFirst()) : output.name
name = name.hasSuffix(".q") ? String(name.dropLast(2)) : name
name = name.hasSuffix(".d") ? String(name.dropLast(2)) : name
outputMap[name] = i
}

Expand Down
77 changes: 27 additions & 50 deletions Sources/Fault/Entries/atpg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,12 @@ extension Fault {

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

@Option(name: [.short, .long], help: "Inputs to ignore. May be specified multiple times.")
var ignoring: [String] = []

@Flag(help: "Hold ignored inputs in the simulation to low instead of high.")
var holdLow: Bool = false


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

@Option(help: "Clock name to add to --ignoring")
var clock: String
@OptionGroup
var bypass: BypassOptions

@Option(help: "If provided, this JSON file's test vectors are simulated and no generation is attempted.")
var externalTVSet: String?
Expand Down Expand Up @@ -115,17 +109,9 @@ extension Fault {
)
}

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

ignoring.append(clock)

let behavior
= [Simulator.Behavior](
repeating: holdLow ? .holdLow : .holdHigh,
count: ignoring.count
)

// MARK: Importing Python and Pyverilog

let parse = Python.import("pyverilog.vparser.parser").parse
Expand Down Expand Up @@ -214,17 +200,17 @@ extension Fault {
var inputsMinusIgnored: [Port] = []
if etvSetVectors.count == 0 {
inputsMinusIgnored = inputs.filter {
!ignoring.contains($0.name)
!bypass.bypassedInputs.contains($0.name)
}
} else {
etvSetInputs.sort { $0.ordinal < $1.ordinal }
inputsMinusIgnored = etvSetInputs.filter {
!ignoring.contains($0.name)
!bypass.bypassedInputs.contains($0.name)
}
}

for (_, port) in ports {
if ignoring.contains(port.name) {
if bypass.bypassedInputs.contains(port.name) {
continue
}
if port.width == 1 {
Expand Down Expand Up @@ -285,8 +271,7 @@ extension Fault {
with: models,
ports: ports,
inputs: inputsMinusIgnored,
ignoring: Set(ignoring),
behavior: behavior,
bypassingWithBehavior: bypass.simulationValues,
outputs: outputs,
initialVectorCount: tvCount,
incrementingBy: increment,
Expand All @@ -297,7 +282,7 @@ extension Fault {
initialTVInfo: initialTVInfo,
externalTestVectors: etvSetVectors,
sampleRun: sampleRun,
clock: clock,
clock: bypass.clock,
defines: Set(defines),
using: iverilogExecutable,
with: vvpExecutable
Expand All @@ -311,36 +296,28 @@ extension Fault {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

let tvInfo = TVInfo(
let rawTVInfo = TVInfo(
inputs: inputsMinusIgnored,
outputs: outputs,
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)")
try encoder.encode(tvInfo).write(to: URL(fileURLWithPath: jsonOutput))

let data = try encoder.encode(tvInfo)

let svfString = try SerialVectorCreator.create(tvInfo: tvInfo)

guard let string = String(data: data, encoding: .utf8)
else {
throw "Could not create utf8 string."
}
try File.open(jsonOutput, mode: .write) {
print("Writing generated test vectors in Fault JSON format to \(jsonOutput)")
try $0.print(string)
}

try File.open(svfOutput, mode: .write) {
print("Writing generated test vectors in SVF format to \(svfOutput)")
try $0.print(svfString)
}

if let faultPointOutput = outputFaultPoints {
print("Writing YAML file of fault points to \(faultPointOutput)")
try File.open(faultPointOutput, mode: .write) {
try $0.write(string: YAMLEncoder().encode(faultPoints.sorted()))
}
}
// try File.open(svfOutput, mode: .write) {
// print("Writing generated test vectors in SVF format to \(svfOutput)…")
// try $0.print(try SerialVectorCreator.create(tvInfo: tvInfo))
// }

if let coverageMetaFilePath = outputCoverageMetadata {
print("Writing YAML file of final coverage metadata to \(coverageMetaFilePath)")
Expand Down
71 changes: 39 additions & 32 deletions Sources/Fault/Entries/bench.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import BigInt
extension Fault {
struct Bench: ParsableCommand {
static let configuration = CommandConfiguration(
abstract: "Generate a benchmark file from Verilog or JSON cell models."
abstract: "Generate a .bench file from Verilog models."
)

@Option(name: [.short, .long], help: "Path to the output file. (Default: input + .bench)")
Expand All @@ -45,7 +45,7 @@ extension Fault {
throw ValidationError("Cell model file '\(cellModel)' not found.")
}

let output = self.output ?? "\(file).bench"
let output = self.output ?? file.replacingExtension(".cut.v", with: ".bench")

var cellModelsFile = cellModel

Expand Down Expand Up @@ -135,23 +135,21 @@ extension Fault {
}

let (_, inputs, outputs) = try Port.extract(from: definition)

var inputNames: [String] = []
var usedInputs: [String] = []
var floatingOutputs: [String] = []

var allWires: Set<String> = []
var usedWires: Set<String> = []
var benchStatements = ""

for input in inputs {
if input.width > 1 {
let range = (input.from > input.to) ? input.to ... input.from : input.from ... input.to
for index in range {
for index in input.bits {
let name = "\(input.name)[\(index)]"
inputNames.append(name)
allWires.insert(name)
benchStatements += "INPUT(\(name)) \n"
}
} else {
let name = input.name
inputNames.append(name)
allWires.insert(name)
benchStatements += "INPUT(\(name)) \n"
}
}
Expand All @@ -170,55 +168,65 @@ extension Fault {

for hook in instance.portlist {
let portname = String(describing: hook.portname)
let argname = BenchCircuit.represent(hook.argname)
let type = Python.type(hook.argname).__name__

if portname == cell.output {
outputs.append(argname)
if type == "Pointer" {
outputs.append("\(hook.argname.var)[\(hook.argname.ptr)]")
} else {
outputs.append(String(describing: hook.argname))
}
} else {
inputs[portname] = argname
if type == "Pointer" {
inputs[portname] = "\(hook.argname.var)[\(hook.argname.ptr)]"
} else {
inputs[portname] = String(describing: hook.argname)
}
}
}

let statements = try cell.extract(name: instanceName, inputs: inputs, output: outputs)
benchStatements += "\(statements) \n"

usedInputs.append(contentsOf: Array(inputs.values))
for used in inputs.values {
usedWires.insert(used)
}
for new: String in outputs {
allWires.insert(new)
}

} else if type == "Assign" {
let right = BenchCircuit.represent(item.right.var)
let left = BenchCircuit.represent(item.left.var)

if right == "1'b0" || right == "1'h0" {
print("[Warning]: Constants are not recognized by atalanta. Removing \(left) associated gates and nets..")
floatingOutputs.append(left)
print("[Warning]: Constants are not supported in the bench format.")
} else {
let statement = "\(left) = BUFF(\(right)) \n"
benchStatements += statement

usedInputs.append(right)
usedWires.insert(right)
}
}
}

let ignoredInputs = inputNames.filter { !usedInputs.contains($0) }
print("Found \(ignoredInputs.count) floating inputs.")

let filteredOutputs = outputs.filter { !floatingOutputs.contains($0.name) }
for output in filteredOutputs {
for output in outputs {
if output.width > 1 {
let range = (output.from > output.to) ? output.to ... output.from : output.from ... output.to
for index in range {
benchStatements += "OUTPUT(\(output.name)[\(index)]) \n"
for index in output.bits {
let name = "\(output.name)[\(index)]"
usedWires.insert(name)
benchStatements += "OUTPUT(\(name)) \n"
}
} else {
benchStatements += "OUTPUT(\(output.name)) \n"
let name = output.name
usedWires.insert(name)
benchStatements += "OUTPUT(\(name)) \n"
}
}

var floatingStatements = ""
for input in ignoredInputs {
floatingStatements += "OUTPUT(\(input)) \n"
}
// for unused in allWires.subtracting(usedWires) {
// benchStatements += "OUTPUT(\(unused))\n"
// }

let boilerplate = """
# Bench for \(definition.name)
Expand All @@ -228,7 +236,6 @@ extension Fault {

try File.open(output, mode: .write) {
try $0.print(boilerplate)
try $0.print(floatingStatements.dropLast())
try $0.print(benchStatements)
}

Expand Down
Loading

0 comments on commit 3182267

Please sign in to comment.