Skip to content

Commit

Permalink
Explicit Muxes in Scan-chain and SCL Configuration YAMLs (#40)
Browse files Browse the repository at this point in the history
* Created YAML configuration file for supported SCLs with the ability to define:
  * D-flipflops and their D/Q portnames (if for some godforsaken reason the ports are not named D and Q)
  * Optionally, a multiplexer to use for scan-chain stitching
    * If the multiplexer exists, it takes priority, otherwise, a ternary operation is used
* Updated Swift requirement to 5.4+
* Updated macOS requirement to 11+
* Ran [SwiftFormat](https://github.com/nicklockwood/SwiftFormat)'s default ruleset on all files.
  • Loading branch information
donn authored Jan 1, 2024
1 parent 54e8665 commit 8bfd648
Show file tree
Hide file tree
Showing 38 changed files with 1,317 additions and 773 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ Netlists
*.test
*.log
*.vvp
parsetab.py
parsetab.py

.swiftpm/
abc.history
1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5.4
10 changes: 2 additions & 8 deletions Contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@ Make your changes and then submit them as a pull requests to the `main` branch.

Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests.

## The Approval Process
For a PR to be merged, there are two requirements:

- It must pass all automated checks.
- An OpenLane team member must inspect and approve the PR.

# Licensing and Copyright
Please add you (or your employer's) copyright headers to any files to which you have made major edits.
Please add your (or your employer's) copyright headers to any files to which you have made major edits.

Please note all code contributions must have the same license as Fault, i.e., the Apache License, version 2.0.
Please note all code contributions must have the same license as Fault, i.e., the Apache License, version 2.0.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ RUN cp /lib64/libtcl8.5.so /build/lib
# Fault Setup
WORKDIR /fault
COPY . .
ENV CC=clang
ENV CXX=clang++
RUN swift build --static-swift-stdlib -c release
RUN cp /fault/.build/x86_64-unknown-linux-gnu/release/Fault /build/bin/fault
WORKDIR /
Expand All @@ -93,4 +95,4 @@ ENV PATH=/build/bin:$PATH\
FAULT_IVERILOG=/build/bin/iverilog\
FAULT_VVP=/build/bin/vvp

CMD [ "/bin/bash" ]
CMD [ "/bin/bash" ]
9 changes: 9 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@
"revision": "c77231820148515a77e9bba5016a57e5a88ef007",
"version": null
}
},
{
"package": "Yams",
"repositoryURL": "https://github.com/jpsim/Yams.git",
"state": {
"branch": null,
"revision": "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3",
"version": "5.0.6"
}
}
]
},
Expand Down
13 changes: 7 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// swift-tools-version:5.0
// swift-tools-version:5.4
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "Fault",
platforms: [
.macOS(.v10_13) // executableURL and a bunch of other things are not available before High Sierra
.macOS(.v11), // 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 @@ -15,19 +15,20 @@ let package = Package(
.package(url: "https://github.com/pvieito/PythonKit", .branch("master")),
.package(url: "https://github.com/pvieito/CommandLineKit", .branch("master")),
.package(url: "https://github.com/donn/Defile.git", from: "5.2.1"),
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.2.1")
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.2.1"),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"),
],
targets: [
// 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.
.target(
.executableTarget(
name: "Fault",
dependencies: ["PythonKit", "CommandLineKit", "Defile", "OrderedDictionary", "BigInt"],
dependencies: ["PythonKit", "CommandLineKit", "Defile", "OrderedDictionary", "BigInt", "Yams"],
path: "Sources"
),
.testTarget(
name: "FaultTests",
dependencies: ["Fault"]
)
),
]
)
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# 🧪 Fault
![Swift 5.2+](https://img.shields.io/badge/Swift-5.2-orange?logo=swift) ![Docker Image Available for x86-64](https://img.shields.io/static/v1?logo=docker&label=docker&message=x86_64) ![AppImage Available for Linux x86-64](https://img.shields.io/static/v1?label=appimage&message=x86_64&color=blue)
![Swift 5.4+](https://img.shields.io/badge/Swift-5.4-orange?logo=swift) ![Docker Image Available for x86-64](https://img.shields.io/static/v1?logo=docker&label=docker&message=x86_64) ![AppImage Available for Linux x86-64](https://img.shields.io/static/v1?label=appimage&message=x86_64&color=blue)

Fault is a complete open source design for testing (DFT) Solution that includes automatic test pattern generation for netlists, scan chain stitching, synthesis scripts and a number of other convenience features.

Expand Down
67 changes: 36 additions & 31 deletions Sources/Fault/Bench.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
// 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 Foundation
import PythonKit

struct BenchCircuit: Codable {
var cells: [BenchCell]

init(cells: [BenchCell]){
init(cells: [BenchCell]) {
self.cells = cells
}

static func extract(definitions: PythonObject) throws -> [BenchCell] {

var cells: [BenchCell] = []
for definition in definitions {

let type = Python.type(definition).__name__

if type == "ModuleDef" {

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

var cellStatements: [String] = []
var cellOutput: String = ""

var cellOutput = ""
for output in outputs {
cellOutput = String(describing: output.name)
}
Expand All @@ -33,23 +44,21 @@ struct BenchCircuit: Codable {
}

for item in definition.items {

let type = Python.type(item).__name__

if type == "InstanceList" {
let instance = item.instances[0]

let outArgname = String(describing: instance.portlist[0].argname)
let output = (outArgname == cellOutput) ? outArgname : "__\(outArgname)___"
let outArgname = String(describing: instance.portlist[0].argname)
let output = (outArgname == cellOutput) ? outArgname : "__\(outArgname)___"

var benchStatement = "("
for hook in instance.portlist[1...]{
for hook in instance.portlist[1...] {
let argname = String(describing: hook.argname)

if cellInputs.contains(argname) {
benchStatement += "\(hook.argname), "
}
else {
} else {
benchStatement += "__\(hook.argname)___, "
}
}
Expand All @@ -60,25 +69,20 @@ struct BenchCircuit: Codable {
switch instance.module {
case "and":
cellStatements.append("\(output) = AND" + benchStatement)
break
case "or":
cellStatements.append("\(output) = OR" + benchStatement)
break
case "xor":
let inputA = instance.portlist[1].argname
let inputB = instance.portlist[2].argname
cellStatements.append(contentsOf: [
"__or_out___ = OR(\(inputA), \(inputB))",
"__nand_out___ = NAND(\(inputA), \(inputB))",
"\(output) = AND(__or_out___, __nand_out___)"
"\(output) = AND(__or_out___, __nand_out___)",
])
break
case "buf":
cellStatements.append("\(output) = BUFF" + benchStatement)
break
case "not":
cellStatements.append("\(output) = NOT" + benchStatement)
break
default:
print("[Warning]: can't expand \(instance.module) in \(cellName) to primitive cells")
}
Expand All @@ -97,7 +101,6 @@ struct BenchCircuit: Codable {

return cells
}

}

struct BenchCell: Codable {
Expand All @@ -111,46 +114,48 @@ struct BenchCell: Codable {
inputs: [String],
output: String,
statements: [String]
){
) {
self.name = name
self.inputs = inputs
self.output = output
self.statements = statements
}

func extract(name: String, inputs: [String:String], output: [String]) throws -> String {
func extract(name: String, inputs: [String: String], output: [String]) throws -> String {
do {
let regexOutput = try NSRegularExpression(pattern: "\(self.output) = ")
let regexWires = try NSRegularExpression(pattern: "___")
let outputName = (output[0].hasPrefix("\\")) ? "\\\(output[0])" : "\(output[0])"

var benchStatements = self.statements
var benchStatements = statements
for (index, _) in statements.enumerated() {

var range = NSRange(benchStatements[index].startIndex..., in: benchStatements[index])
benchStatements[index] = regexOutput.stringByReplacingMatches(
in: benchStatements[index],
options: [],
range: range,
withTemplate: "\(outputName) = ")
withTemplate: "\(outputName) = "
)

range = NSRange(benchStatements[index].startIndex..., in: benchStatements[index])
range = NSRange(benchStatements[index].startIndex..., in: benchStatements[index])
benchStatements[index] = regexWires.stringByReplacingMatches(
in: benchStatements[index],
options: [],
range: range,
withTemplate: "__\(name)")
withTemplate: "__\(name)"
)

for input in self.inputs {
let regexInput = try NSRegularExpression(pattern: "(?<=\\(|,)\\s*\(input)(?=\\s*,|\\s*\\))")
let name = (inputs[input]!.hasPrefix("\\")) ? "\\\(inputs[input]!)" : "\(inputs[input]!)"

range = NSRange(benchStatements[index].startIndex..., in: benchStatements[index])
range = NSRange(benchStatements[index].startIndex..., in: benchStatements[index])
benchStatements[index] = regexInput.stringByReplacingMatches(
in: benchStatements[index],
options: [],
range: NSRange(benchStatements[index].startIndex..., in: benchStatements[index]),
withTemplate: name )
withTemplate: name
)
}
}

Expand All @@ -166,4 +171,4 @@ struct BenchCell: Codable {
return ""
}
}
}
}
44 changes: 29 additions & 15 deletions Sources/Fault/BoundaryScanRegister.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// 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 Foundation
import PythonKit

Expand All @@ -6,7 +20,7 @@ class BoundaryScanRegisterCreator {
private var inputName: String
private var outputName: String
var counter: Int = 0

var clock: String
var reset: String
var resetActive: Simulator.Active
Expand All @@ -30,22 +44,22 @@ class BoundaryScanRegisterCreator {
using Node: PythonObject
) {
self.name = name
self.inputName = "\(name)_input"
self.outputName = "\(name)_output"
inputName = "\(name)_input"
outputName = "\(name)_output"

self.clock = clock
self.clockIdentifier = Node.Identifier(clock)
clockIdentifier = Node.Identifier(clock)

self.reset = reset
self.resetIdentifier = Node.Identifier(reset)
resetIdentifier = Node.Identifier(reset)

self.resetActive = resetActive

self.testing = testing
self.testingIdentifier = Node.Identifier(testing)
testingIdentifier = Node.Identifier(testing)

self.shift = shift
self.shiftIdentifier = Node.Identifier(shift)
shiftIdentifier = Node.Identifier(shift)

self.Node = Node
}
Expand All @@ -66,8 +80,8 @@ class BoundaryScanRegisterCreator {
let ordinalConstant = Node.Constant(ordinal)

let name = input ? inputName : outputName
let dinArg = (max == 0) ? dinIdentifier: Node.Pointer(dinIdentifier, ordinalConstant)
let doutArg = (max == 0) ? doutIdentifier: Node.Pointer(doutIdentifier, ordinalConstant)
let dinArg = (max == 0) ? dinIdentifier : Node.Pointer(dinIdentifier, ordinalConstant)
let doutArg = (max == 0) ? doutIdentifier : Node.Pointer(doutIdentifier, ordinalConstant)

let portArguments = [
Node.PortArg("din", dinArg),
Expand All @@ -77,7 +91,7 @@ class BoundaryScanRegisterCreator {
Node.PortArg("clock", clockIdentifier),
Node.PortArg("reset", resetIdentifier),
Node.PortArg("testing", testingIdentifier),
Node.PortArg("shift", shiftIdentifier)
Node.PortArg("shift", shiftIdentifier),
]

let submoduleInstance = Node.Instance(
Expand All @@ -97,7 +111,7 @@ class BoundaryScanRegisterCreator {
}

var inputDefinition: String {
return """
"""
module \(inputName) (
din,
dout,
Expand All @@ -123,12 +137,12 @@ class BoundaryScanRegisterCreator {
assign sout = store;
assign dout = testing ? store : din;
endmodule
"""
}

var outputDefinition: String {
return """
"""
module \(outputName) (
din,
dout,
Expand All @@ -153,7 +167,7 @@ class BoundaryScanRegisterCreator {
assign sout = store;
assign dout = din;
endmodule
"""
}
}
}
Loading

0 comments on commit 8bfd648

Please sign in to comment.