Open curtisma opened 1 year ago
I would propose adding another Module class called "SchematicModule" that could wrap a schematic for inclusion as a black box similar to "ExternalModule". It would be given the path to the schematic and an enumerated schematic tool type. Then it could use the external tool CLI to netlist the schematic. For example, xscem. Then the netlist could be included as part of the testbench netlist.
Code to netlist an xschem schematic to an ngspice netlist:
def netlist(self):
"""netlist an xschem schematic."""
print(f"netlisting {str(self.schematic_path)}\n to {self.netlist_path}")
self.netlist_path.parent.rmdir()
self.netlist_path.parent.mkdir(parents=True,exist_ok=True)
sch_picture_path = self.netlist_path.parent / \
(self.schematic_path.stem + ".svg")
run_result=subprocess.run(["xschem", "-q",
"-n", "-o", str(self.netlist_path.parent),
"--svg", "--plotfile", str(sch_picture_path),
"-l", str(self.netlist_log_path),
"--rcfile", str(self.xschemrc_path),
str(self.schematic_path)],
capture_output=True, check=True)
Full Class Code:
class xschem_testbench:
#default_root_result_path = Path.home() / "sim_results"
xschemrc_path = Path("/foss/pdks/sky130A/libs.tech/xschem/xschemrc")
def __init__(self, name: str, schematic_path: Union[Path, str],
result_path: optional_path = None) -> None:
self.name = name
self.schematic_path = Path(schematic_path)
if result_path is not None:
self.result_path = Path(result_path)
else:
#self.result_path = self.default_root_result_path / self.name
self.result_path = self.schematic_path.parent
netlist_filename = self.schematic_path.stem +".spice"
self.netlist_path = self.result_path / "netlist" / netlist_filename
self.netlist_log_path = self.netlist_path.parent / ".netlisting.log"
soa_log_filename = self.schematic_path.stem + ".soa.log"
self.soa_log_path = self.result_path.parent / soa_log_filename
sim_log_filename = self.schematic_path.stem + ".sim.log"
self.sim_log_path = self.result_path.parent / sim_log_filename
def netlist(self):
"""netlist an xschem schematic."""
print(f"netlisting {str(self.schematic_path)}\n to {self.netlist_path}")
self.netlist_path.parent.rmdir()
self.netlist_path.parent.mkdir(parents=True,exist_ok=True)
sch_picture_path = self.netlist_path.parent / \
(self.schematic_path.stem + ".svg")
run_result=subprocess.run(["xschem", "-q",
"-n", "-o", str(self.netlist_path.parent),
"--svg", "--plotfile", str(sch_picture_path),
"-l", str(self.netlist_log_path),
"--rcfile", str(self.xschemrc_path),
str(self.schematic_path)],
capture_output=True, check=True)
# if len(run_result.stdout) > 0:
# print(run_result.stdout)
#
#os.system(f'xschem -q'
# f' -n {self.netlist_path}'
# f' {self.schematic_path}')
def simulate(self) -> ngspice_result:
"""Simulate using ngspice"""
if not self.netlist_path.is_file():
raise RuntimeError("Testbench netlist does not exist.")
print(f'Simulating {self.netlist_path.name} at \n'
f' {self.netlist_path}')
raw_output_path = f'{self.result_path/self.name}.raw'
output_path = f'{self.result_path/self.name}.out'
run_result=subprocess.run(
["ngspice", "-b",
"-o", str(output_path),
"-r", raw_output_path,
f'--soa-log={self.soa_log_path}',
str(self.netlist_path),
],
capture_output=True, check=True)
with open(self.sim_log_path,mode="w") as log:
log.write(str(run_result.stdout))
return ngspice_result(self, output_path, raw_output_path)
def run_schematic(self) -> ngspice_result:
self.netlist()
return self.simulate()
@classmethod
def run(cls, name: str, schematic_path: Union[Path, str]):
"Netlists and then simulates a schematic"
tb = cls(name, schematic_path)
result = tb.run_schematic()
result.print_summary()
I'm going to try this out as part of evaluating a bandgap we're working on.
The current version I'm working on will just support xschem schematics but we could consider adding other formats in the future such as:
Thanks for digging in here!
Some background: Hdl21 really only (directly) knows about one import/ export format, and that is VLSIR. And that's on purpose, so that the code for, for example, translating to industry-standard formats can be shared with other projects. The primary implementations of this are in VlsirTools.
Now, the primary netlist-parsing in this whole wide family of software is here: https://github.com/dan-fritchman/Netlist Which:
One could certainly write a separate netlist parser, and cover a different set of the universe of available netlist content. (Noting there are so many fun cases to discover out there.)
My preference would be to -
The latter should be pretty straightforward, and pretty sane. They each have concepts of, say, Module
and Param
, mappable between each other.
Alternately netlist-parsing could produce VLSIR directly - but this would require adding a whole buncha stuff to the VLSIR schema. Netlist
's parser includes things like math expression trees (as a traditional compiler would have), families of binned models, etc.
On the types this all produces - I don't see why we'd need another specialty "kind of" ExternalModule
. Code can just return ExternalModule
s, whatever their ultimate source.
Picking up where this left off... because I have a shiny Op-Amp netlist I want to use and I'd rather complain and muse about it than actually implement it... so, I'm seeing there are a few proposals on the table here:
ExternalModules
on the fly.from_proto
.Either way, these will all sit flush with a <LIBRARY>.parse_netlist()
function that will map a netlist to an external module, no matter what pipeline is chosen. I feel as if the choice being made here comes down to the boundaries between VLSIR, VlsirTools and HDL21.
The way I imagine the project is as follows:
So, in my head, proposal 3 makes the most sense, as we're expanding VlsirTools into a more general simulator utilities library that allows whatever goes into and comes out of a simulator to be translated into and out of VLSIR. Although this then begs the question if all simulator stuff should then live in VlsirTools
, but let's not get ahead of ourselves here.
So yeah, what does VLSIR team make of all this, before we get building a pipeline through 3 repositories?
Yeah reiterating my prior commentary - I would very much recommend starting with the parsers here:
https://github.com/dan-fritchman/Netlist
And turning its data model into VLSIR.
Netlist-parsing is maybe like C parsing, or XML parsing, or some-such. Seems (and is!) really easy to get rolling. Then one notices the edge-cases, one at a time, until they're like 98% of the action. Having written all the corner cases of that parser already, I would not recommend re-discovering them. (I am reminded of this right now by using another project which went the "yet another custom parser" route... and stinks.)
Also agree there's more git repos at play than would be ideal. Pulling that into the Vlsir
repo could make sense.
After a re-read, I realize that's basically your #3. So, agree.
I'm interested in using Hdl21 for creating a test bench for a design already defined in a traditional schematic. In this case, it is coming from an xschem schematic.
It would also be great to be able to import a spice netlist in general as a module. This would allow some sub-blocks to be defined in a schematic based on user preference.
I was thinking I could start with a netlist of the dut design and import it as a module into Hdl21. I could then set up the testbench using Hdl21.
Are there any existing import options? If not, do you have any recommendations on the best way to implement this functionality?
One other nice feature would be if you could create a module which is a wrapper pointing to an xschem schematic file (ascii) which it can import as a module directly, handling the netlisiting using the xschem CLI.