From 88be7fcb83551cc4570bde12a4f19633c2a52660 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Mon, 15 Jan 2024 14:53:08 +0200 Subject: [PATCH] Generalized `RNG` into `TVGenerator` * Generation reworked: Each test vector is generated entirely ahead of time then cut into bits instead of generated segment by segment * Added new TVGenerator, `PatternGenerator`, that is not random and uses the following pattern(s) depending on the iteration count: * All 0 * All 1 * Half 0, Half 1 * Half 1, Half 0 * Alternating 0s and 1s * Alternating 1s and 0s * Moving `max(1, min(32, bits/4))` window of 1s (even) and the complement of that (odd) * TVGenerators now take a seed, fixed default seed but can be changed over CLI * Fixed test * Incorporated `ARC4RandomNumberGenerator`from Swift TensorFlow sources (takes a seed) --- Sources/Fault/Entries/main.swift | 37 ++-- Sources/Fault/RNG.swift | 112 ++++++++++++ Sources/Fault/RNGFactory.swift | 41 ----- Sources/Fault/Simulation.swift | 26 +-- Sources/Fault/TVGenerator.swift | 290 +++++++++++++++++------------- Tests/FaultTests/FaultTests.swift | 2 +- 6 files changed, 313 insertions(+), 195 deletions(-) create mode 100644 Sources/Fault/RNG.swift delete mode 100644 Sources/Fault/RNGFactory.swift diff --git a/Sources/Fault/Entries/main.swift b/Sources/Fault/Entries/main.swift index 5e0c46e..9defb01 100644 --- a/Sources/Fault/Entries/main.swift +++ b/Sources/Fault/Entries/main.swift @@ -32,6 +32,7 @@ let yosysExecutable = env["FAULT_YOSYS"] ?? "yosys" _ = [ // Register all RNGs SwiftRNG.registered, LFSR.registered, + PatternGenerator.registered, ] _ = [ // Register all TVGens Atalanta.registered, @@ -88,7 +89,8 @@ func main(arguments: [String]) -> Int32 { let defaultTVIncrement = "50" let defaultMinimumCoverage = "80" let defaultCeiling = "1000" - let defaultRNG = "swift" + let defaultTVGen = "swift" + let defaultSeed: UInt = 0xDEADCAFEDEADF00D let version = BoolOption( shortFlag: "V", @@ -163,18 +165,24 @@ func main(arguments: [String]) -> Int32 { ) cli.addOptions(ceiling) - let rng = StringOption( - longFlag: "rng", - helpMessage: "Type of the RNG used in Internal TV Generation: LFSR or swift. (Default: swift.)" - ) - cli.addOptions(rng) - let tvGen = StringOption( shortFlag: "g", longFlag: "tvGen", - helpMessage: "Use an external TV Generator: Atalanta or PODEM. (Default: Internal.)" + helpMessage: "Type of the (pseudo-random) internal Test Vector generator: \(TVGeneratorFactory.validNames.joined(separator: "|")) (Default: \(defaultTVGen))" ) cli.addOptions(tvGen) + + let rngSeed = StringOption( + longFlag: "rngSeed", + helpMessage: "A \(MemoryLayout.size)-byte value to use as an RNG seed for test vector generators, provided as a hexadecimal string (without 0x). (Default: \(String(defaultSeed, radix: 16)))" + ) + cli.addOptions(rngSeed) + + let etvGen = StringOption( + longFlag: "etvGen", + helpMessage: "Use an external TV Generator: Atalanta or PODEM. (Default: Internal.)" + ) + cli.addOptions(etvGen) let bench = StringOption( shortFlag: "b", @@ -261,13 +269,13 @@ func main(arguments: [String]) -> Int32 { return EX_USAGE } - let randomGenerator = rng.value ?? defaultRNG + let tvGenName = tvGen.value ?? defaultTVGen guard let tvAttempts = Int(testVectorCount.value ?? defaultTVCount), let tvIncrement = Int(testVectorIncrement.value ?? defaultTVIncrement), let tvMinimumCoverageInt = Int(minimumCoverage.value ?? defaultMinimumCoverage), - Int(ceiling.value ?? defaultCeiling) != nil, URNGFactory.validNames.contains(randomGenerator), (tvGen.value == nil) == (bench.value == nil) + Int(ceiling.value ?? defaultCeiling) != nil, TVGeneratorFactory.validNames.contains(tvGenName), (etvGen.value == nil) == (bench.value == nil) else { cli.printUsage() return EX_USAGE @@ -369,9 +377,9 @@ func main(arguments: [String]) -> Int32 { print("Read \(etvSetVectors.count) externally-generated vectors to verify.") } - if let tvGenerator = tvGen.value, ETVGFactory.validNames.contains(tvGenerator) { + if let tvGenerator = etvGen.value, ETVGFactory.validNames.contains(tvGenerator) { let etvgen = ETVGFactory.get(name: tvGenerator)! - let benchUnwrapped = bench.value! // Program exits if tvGen.value isn't nil and bench.value is or vice versa + let benchUnwrapped = bench.value! // Program exits if etvGen.value isn't nil and bench.value is or vice versa if !fileManager.fileExists(atPath: benchUnwrapped) { Stderr.print("Bench file '\(benchUnwrapped)' not found.") @@ -395,6 +403,8 @@ func main(arguments: [String]) -> Int32 { String(etvSetVectors.count) ) )! + + let finalRNGSeed = rngSeed.value != nil ? UInt(rngSeed.value!, radix: 16)! : defaultSeed do { let (ports, inputs, outputs) = try Port.extract(from: definition) @@ -493,7 +503,8 @@ func main(arguments: [String]) -> Int32 { incrementingBy: tvIncrement, minimumCoverage: tvMinimumCoverage, ceiling: finalTvCeiling, - randomGenerator: randomGenerator, + tvGenerator: TVGeneratorFactory.get(name: tvGenName)!, + rngSeed: finalRNGSeed, initialTVInfo: initialTVInfo, externalTestVectors: etvSetVectors, sampleRun: sampleRun.value, diff --git a/Sources/Fault/RNG.swift b/Sources/Fault/RNG.swift new file mode 100644 index 0000000..5158c29 --- /dev/null +++ b/Sources/Fault/RNG.swift @@ -0,0 +1,112 @@ +//===-- Random.swift ------------------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// A (pseudo-)random number generation library. The library separates concerns +// into engines which generate random bytes and distributions which use an +// engine to generate values from some statistical distribution. +// +//===----------------------------------------------------------------------===// + +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) +import Darwin +#else +import Glibc +#endif + +/// A type that provides seedable deterministic pseudo-random data. +/// +/// A SeedableRandomNumberGenerator can be used anywhere where a +/// RandomNumberGenerator would be used. It is useful when the pseudo-random +/// data needs to be reproducible across runs. +/// +/// Conforming to the SeedableRandomNumberGenerator Protocol +/// ======================================================== +/// +/// To make a custom type conform to the `SeedableRandomNumberGenerator` +/// protocol, implement the `init(seed: [UInt8])` initializer, as well as the +/// requirements for `RandomNumberGenerator`. The values returned by `next()` +/// must form a deterministic sequence that depends only on the seed provided +/// upon initialization. +public protocol SeedableRandomNumberGenerator: RandomNumberGenerator { + init(seed: [UInt8]) + init(seed: T) +} + +extension SeedableRandomNumberGenerator { + public init(seed: T) { + var newSeed: [UInt8] = [] + for i in 0..> (UInt8.bitWidth * i))) + } + self.init(seed: newSeed) + } +} + +/// An implementation of `SeedableRandomNumberGenerator` using ARC4. +/// +/// ARC4 is a stream cipher that generates a pseudo-random stream of bytes. This +/// PRNG uses the seed as its key. +/// +/// ARC4 is described in Schneier, B., "Applied Cryptography: Protocols, +/// Algorithms, and Source Code in C", 2nd Edition, 1996. +/// +/// An individual generator is not thread-safe, but distinct generators do not +/// share state. The random data generated is of high-quality, but is not +/// suitable for cryptographic applications. +@frozen +public struct ARC4RandomNumberGenerator: SeedableRandomNumberGenerator { + public static var global = ARC4RandomNumberGenerator(seed: UInt32(time(nil))) + var state: [UInt8] = Array(0...255) + var iPos: UInt8 = 0 + var jPos: UInt8 = 0 + + /// Initialize ARC4RandomNumberGenerator using an array of UInt8. The array + /// must have length between 1 and 256 inclusive. + public init(seed: [UInt8]) { + precondition(seed.count > 0, "Length of seed must be positive") + precondition(seed.count <= 256, "Length of seed must be at most 256") + var j: UInt8 = 0 + for i: UInt8 in 0...255 { + j &+= S(i) &+ seed[Int(i) % seed.count] + swapAt(i, j) + } + } + + // Produce the next random UInt64 from the stream, and advance the internal + // state. + public mutating func next() -> UInt64 { + var result: UInt64 = 0 + for _ in 0.. UInt8 { + return state[Int(index)] + } + + // Helper to swap elements of the state. + private mutating func swapAt(_ i: UInt8, _ j: UInt8) { + state.swapAt(Int(i), Int(j)) + } + + // Generates the next byte in the keystream. + private mutating func nextByte() -> UInt8 { + iPos &+= 1 + jPos &+= S(iPos) + swapAt(iPos, jPos) + return S(S(iPos) &+ S(jPos)) + } +} diff --git a/Sources/Fault/RNGFactory.swift b/Sources/Fault/RNGFactory.swift deleted file mode 100644 index 09dba9c..0000000 --- a/Sources/Fault/RNGFactory.swift +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2019 The American University in Cairo -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import BigInt -import Foundation - -protocol URNG { - init(allBits: Int) - func generate(bits: Int) -> BigUInt -} - -enum URNGFactory { - private static var registry: [String: URNG.Type] = [:] - - static func register(name: String, type: T.Type) -> Bool { - registry[name] = type - return true - } - - static func get(name: String) -> URNG.Type? { - guard let metaType = registry[name] else { - return nil - } - return metaType - } - - static var validNames: [String] { - [String](registry.keys) - } -} diff --git a/Sources/Fault/Simulation.swift b/Sources/Fault/Simulation.swift index 638faf7..fbdad0f 100644 --- a/Sources/Fault/Simulation.swift +++ b/Sources/Fault/Simulation.swift @@ -231,7 +231,8 @@ enum Simulator { incrementingBy increment: Int, minimumCoverage: Float, ceiling: Int, - randomGenerator: String, + tvGenerator: TVGenerator.Type, + rngSeed: UInt, initialTVInfo: TVInfo? = nil, externalTestVectors: [TestVector], sampleRun: Bool, @@ -266,7 +267,7 @@ enum Simulator { let simulateOnly = (externalTestVectors.count != 0) let totalBitWidth = inputs.reduce(0) { $0 + $1.width } - let backupRng: URNG = URNGFactory.get(name: randomGenerator)!.init(allBits: totalBitWidth) + var rng: TVGenerator = tvGenerator.init(allBits: totalBitWidth, seed: rngSeed) while coverage < minimumCoverage, totalTVAttempts < ceiling { if totalTVAttempts > 0 { @@ -280,30 +281,15 @@ enum Simulator { var testVectors: [TestVector] = [] for index in 0 ..< tvAttempts { let overallIndex = totalTVAttempts + index - - var rng: URNG = backupRng - if overallIndex == 0 { - rng = PatternGenerator(allBits: totalBitWidth, pattern: .allZero, complement: false) - } else if overallIndex == 1 { - rng = PatternGenerator(allBits: totalBitWidth, pattern: .allZero, complement: true) - } else if overallIndex == 2 { - rng = PatternGenerator(allBits: totalBitWidth, pattern: .alternating, complement: false) - } else if overallIndex == 3 { - rng = PatternGenerator(allBits: totalBitWidth, pattern: .alternating, complement: true) - } else if overallIndex == 4 { - rng = PatternGenerator(allBits: totalBitWidth, pattern: .halfAndHalf, complement: false) - } else if overallIndex == 5 { - rng = PatternGenerator(allBits: totalBitWidth, pattern: .halfAndHalf, complement: true) - } + rng.generate(count: overallIndex) + // print(rng.current.pad(digits: totalBitWidth, radix: 2)) var testVector: TestVector = [] if simulateOnly { testVector = externalTestVectors[overallIndex] } else { - var assembled: BigUInt = 0 var bitsSoFar = 0 for input in inputs { - let value = rng.generate(bits: input.width) - assembled |= (value << bitsSoFar) + let value = rng.get(bits: input.width) bitsSoFar += input.width testVector.append(value) } diff --git a/Sources/Fault/TVGenerator.swift b/Sources/Fault/TVGenerator.swift index a31b5fc..289ee5c 100644 --- a/Sources/Fault/TVGenerator.swift +++ b/Sources/Fault/TVGenerator.swift @@ -16,24 +16,37 @@ import BigInt import Defile import Foundation -protocol ExternalTestVectorGenerator { - init() - func generate(file: String, module: String) -> ([TestVector], [Port]) + +protocol TVGenerator { + var current: BigUInt { get set } + + init(allBits: Int, seed: UInt) + + func generate(count: Int) } -enum ETVGFactory { - private static var registry: [String: ExternalTestVectorGenerator.Type] = [:] +extension TVGenerator { + mutating func get(bits: Int) -> BigUInt { + let mask = (BigUInt(1) << bits) - 1 + let result = current & mask + current >>= bits + return result + } +} - static func register(name: String, type: T.Type) -> Bool { +enum TVGeneratorFactory { + private static var registry: [String: TVGenerator.Type] = [:] + + static func register(name: String, type: T.Type) -> Bool { registry[name] = type return true } - static func get(name: String) -> ExternalTestVectorGenerator? { + static func get(name: String) -> TVGenerator.Type? { guard let metaType = registry[name] else { return nil } - return metaType.init() + return metaType } static var validNames: [String] { @@ -41,80 +54,28 @@ enum ETVGFactory { } } -class Atalanta: ExternalTestVectorGenerator { - required init() {} - - func generate(file: String, module: String) -> ([TestVector], [Port]) { - let tempDir = "\(NSTemporaryDirectory())" - - let folderName = "\(tempDir)thr\(Unmanaged.passUnretained(Thread.current).toOpaque())" - let _ = "mkdir -p '\(folderName)'".sh() - defer { - let _ = "rm -rf '\(folderName)'".sh() - } - - let output = "\(folderName)/\(module).test" - let atalanta = "atalanta -t \(output) \(file) > /dev/null 2>&1".sh() - - if atalanta != EX_OK { - exit(atalanta) - } - - do { - let (testvectors, inputs) = try TVSet.readFromTest(file: output) - return (vectors: testvectors, inputs: inputs) - } catch { - Stderr.print("Internal software error: \(error)") - exit(EX_SOFTWARE) - } +class SwiftRNG: TVGenerator { + var current: BigUInt + var bits: Int + var rng: RandomNumberGenerator + + required init(allBits bits: Int, seed: UInt) { + self.current = 0 + self.bits = bits + self.rng = ARC4RandomNumberGenerator(seed: seed) } - static let registered = ETVGFactory.register(name: "Atalanta", type: Atalanta.self) -} - -class PODEM: ExternalTestVectorGenerator { - required init() {} - - func generate(file: String, module: String) -> ([TestVector], [Port]) { - let tempDir = "\(NSTemporaryDirectory())" - - let folderName = "\(tempDir)thr\(Unmanaged.passUnretained(Thread.current).toOpaque())" - let _ = "mkdir -p '\(folderName)'".sh() - defer { - let _ = "rm -rf '\(folderName)'".sh() - } - - let output = "\(folderName)/\(module).out" - let podem = "atpg -output \(output) \(file) > /dev/null 2>&1".sh() - - if podem != EX_OK { - exit(podem) - } - do { - let (testvectors, inputs) = try TVSet.readFromText(file: output) - return (vectors: testvectors, inputs: inputs) - } catch { - Stderr.print("Internal software error: \(error)") - exit(EX_SOFTWARE) - } - } - - static let registered = ETVGFactory.register(name: "PODEM", type: PODEM.self) -} - -// MARK: Random Generators - -class SwiftRNG: URNG { - required init(allBits _: Int) {} - - func generate(bits: Int) -> BigUInt { - BigUInt.randomInteger(withMaximumWidth: bits) + func generate(count: Int) { + self.current = BigUInt.randomInteger(withMaximumWidth: bits, using: &self.rng) } - static let registered = URNGFactory.register(name: "swift", type: SwiftRNG.self) + static let registered = TVGeneratorFactory.register(name: "swift", type: SwiftRNG.self) } -class LFSR: URNG { +class LFSR: TVGenerator { + var current: BigUInt + var bits: Int + static let taps: [UInt: [UInt]] = [ // nbits : Feedback Polynomial 2: [2, 1], @@ -155,12 +116,14 @@ class LFSR: URNG { var polynomialHex: UInt let nbits: UInt - required init(allBits _: Int, nbits: UInt) { - let max: UInt = (nbits == 64) ? UInt(pow(Double(2), Double(63)) - 1) : (1 << nbits) - 1 + required init(allBits bits: Int, nbits: UInt, seed: UInt) { + self.seed = seed + self.nbits = nbits + self.bits = bits + self.current = 0 + let polynomial = LFSR.taps[nbits]! - seed = UInt.random(in: 1 ... max) - self.nbits = nbits polynomialHex = 0 for tap in polynomial { @@ -168,8 +131,8 @@ class LFSR: URNG { } } - required convenience init(allBits: Int) { - self.init(allBits: allBits, nbits: 64) + required convenience init(allBits: Int, seed: UInt) { + self.init(allBits: allBits, nbits: 64, seed: seed) } static func parity(number: UInt) -> UInt { @@ -188,7 +151,7 @@ class LFSR: URNG { return seed } - func generate(bits: Int) -> BigUInt { + func generate(count: Int) { var returnValue: BigUInt = 0 var generations = bits / Int(nbits) let leftover = bits % Int(nbits) @@ -201,53 +164,140 @@ class LFSR: URNG { returnValue <<= BigUInt(leftover) returnValue |= BigUInt(rand() % ((1 << leftover) - 1)) } - return returnValue + current = returnValue } - static let registered = URNGFactory.register(name: "LFSR", type: LFSR.self) + static let registered = TVGeneratorFactory.register(name: "LFSR", type: LFSR.self) } -class PatternGenerator: URNG { - enum Pattern { - case allZero - case halfAndHalf - case alternating - } - - let pattern: Pattern - let complement: Bool - var number: BigUInt - - init(allBits: Int, pattern: Pattern, complement: Bool) { - self.pattern = pattern - self.complement = complement - number = BigUInt(0) - switch self.pattern { - case .halfAndHalf: - let halfBits = allBits / 2 - number = (BigUInt(1) << halfBits) - 1 - case .alternating: - for _ in 0 ..< allBits { - number = (number << 1) | ((number & 1) ^ 1) +class PatternGenerator: TVGenerator { + var current: BigUInt = 0 + var bits: Int = 0 + + required init(allBits bits: Int, seed _: UInt) { + self.bits = bits + self.current = 0 + } + + func generate(count: Int) { + let selector = count / 2 + let complement = (count % 2) == 1 + self.current = 0 + if selector == 0 { + // Nothing, it's already all zeroes + } else if selector == 1 { + // Half-and-half + let halfBits = bits / 2 + current = (BigUInt(1) << halfBits) - 1 + } else if selector == 2 { + // Alternating 0s and 1s + for _ in 0 ..< bits { + current = (current << 1) | ((current & 1) ^ 1) } - default: - break + } else { + // Moving (min 32, total / 4)-bit window + let windowShift = (selector - 3) + let windowSize = max(1, min(32, bits / 4)) + let window = (BigUInt(1) << windowSize) - 1 + current |= (window << windowShift) + } + + let mask = (BigUInt(1) << bits) - 1 + current &= mask + + if (complement) { + current ^= mask + } + } + + static let registered = TVGeneratorFactory.register(name: "pattern", type: PatternGenerator.self) +} + + + +// TODO: Unify external and internal TV generators +protocol ExternalTestVectorGenerator { + init() + func generate(file: String, module: String) -> ([TestVector], [Port]) +} + +enum ETVGFactory { + private static var registry: [String: ExternalTestVectorGenerator.Type] = [:] + + static func register(name: String, type: T.Type) -> Bool { + registry[name] = type + return true + } + + static func get(name: String) -> ExternalTestVectorGenerator? { + guard let metaType = registry[name] else { + return nil } + return metaType.init() } - required convenience init(allBits: Int) { - self.init(allBits: allBits, pattern: .allZero, complement: false) + static var validNames: [String] { + [String](registry.keys) } +} - func generate(bits: Int) -> BigUInt { - let mask = (BigUInt(1) << bits) - 1 - let result = number & mask - number >>= bits - // print("returning \(bits) bits: \(result.pad(digits: bits, radix: 2))") - if complement { - return result ^ mask - } else { - return result +class Atalanta: ExternalTestVectorGenerator { + required init() {} + + func generate(file: String, module: String) -> ([TestVector], [Port]) { + let tempDir = "\(NSTemporaryDirectory())" + + let folderName = "\(tempDir)thr\(Unmanaged.passUnretained(Thread.current).toOpaque())" + let _ = "mkdir -p '\(folderName)'".sh() + defer { + let _ = "rm -rf '\(folderName)'".sh() + } + + let output = "\(folderName)/\(module).test" + let atalanta = "atalanta -t \(output) \(file) > /dev/null 2>&1".sh() + + if atalanta != EX_OK { + exit(atalanta) + } + + do { + let (testvectors, inputs) = try TVSet.readFromTest(file: output) + return (vectors: testvectors, inputs: inputs) + } catch { + Stderr.print("Internal software error: \(error)") + exit(EX_SOFTWARE) } } + + static let registered = ETVGFactory.register(name: "Atalanta", type: Atalanta.self) +} + +class PODEM: ExternalTestVectorGenerator { + required init() {} + + func generate(file: String, module: String) -> ([TestVector], [Port]) { + let tempDir = "\(NSTemporaryDirectory())" + + let folderName = "\(tempDir)thr\(Unmanaged.passUnretained(Thread.current).toOpaque())" + let _ = "mkdir -p '\(folderName)'".sh() + defer { + let _ = "rm -rf '\(folderName)'".sh() + } + + let output = "\(folderName)/\(module).out" + let podem = "atpg -output \(output) \(file) > /dev/null 2>&1".sh() + + if podem != EX_OK { + exit(podem) + } + do { + let (testvectors, inputs) = try TVSet.readFromText(file: output) + return (vectors: testvectors, inputs: inputs) + } catch { + Stderr.print("Internal software error: \(error)") + exit(EX_SOFTWARE) + } + } + + static let registered = ETVGFactory.register(name: "PODEM", type: PODEM.self) } diff --git a/Tests/FaultTests/FaultTests.swift b/Tests/FaultTests/FaultTests.swift index e50aa24..392b95e 100644 --- a/Tests/FaultTests/FaultTests.swift +++ b/Tests/FaultTests/FaultTests.swift @@ -127,7 +127,7 @@ final class FaultTests: XCTestCase { try run(steps: [ ["synth", "-l", liberty, "-t", topModule, "-o", fileSynth, "--blackboxModel", "Tests/RTL/integration/buffered_inverter.v", fileName], ["cut", "-o", fileCut, "--blackbox", "BufferedInverter", "--blackboxModel", "Tests/RTL/integration/buffered_inverter.v", "--ignoring", "clk,rst,rstn", fileSynth], - ["-c", models, "-i", reset, "--clock", clock, "-o", fileJson, "--output-fault-points", faultPointsYML, "--output-covered", coverageYml, fileCut], + ["-c", models, "-i", reset, "--clock", clock, "-o", fileJson, "--output-faultPoints", faultPointsYML, "--output-covered", coverageYml, fileCut], ["chain", "-c", models, "-l", liberty, "-o", fileChained, "--clock", clock, "--reset", reset, "--activeLow", "-i", ignoredInputs, fileSynth, "--blackbox", "BufferedInverter", "--blackboxModel", "Tests/RTL/integration/buffered_inverter.v"], ["asm", fileJson, fileChained], ["compact", "-o", "/dev/null", fileJson],