Chips Made From Python
Chip design does not often tend to be thought of as programming, although a complex system-on-chip (SoC) is generally crafted through thousands or millions of lines of code.
For decades chip design has primarily taken place in C-derived, domain-specific hardware description languages, such as Verilog and VHDL. A recent set of hardware description libraries, several based in Python, aim to instead move the chip-design process into modern programming languages.
These developments ride alongside a complementary rise in prominence of the open-source RISC-V instruction set, enabling Python implementations of fully open-source CPUs and SOCs.
This talk will introduce the primary libraries in this space, chips being built with them, and likely future directions for Python's role in silicon design.
This session took place in track PyConDE and was classified suitable for guru domain / guru python by the speaker.
Transcript (auto)
Auto-generated from the recording utilizing Open-Source AI. Speaker labels (Speaker 1, Speaker 2) reflect diarization, not identity. Timestamps refer to the recording.
Speaker 1 [00:03]
All right. Thanks, everyone. I'm Dan, and this is my second PyCon. My first as a speaker. And while I've been using Python for more or less my entire career, what I do is I'm a chip designer. And before founding HW21 this year, I did that at Apple for about the prior decade, primarily on the application processors for iPhones, iPads, and the like. I'll be joining UC Berkeley as a PhD candidate January of next year. And I'm going to talk about the role of Python and friends in the next phase of how custom hardware and particularly silicon get designed. Now, you might wonder if this is going to be about sort of data and sci-fi style stack. It's not. We do love those things and use them. But I'm going to talk about some libraries that we use at an even more integral level of doing our hardware design. And that's going to take a little while to introduce how we do that today before we get to how Python's changing it. And the way I like to introduce that is to start with a thought experiment. Let's imagine in our mind's eye a group of people getting together, making a piece of software. What do they look like? Whether that's your job or not, you probably have a pretty good mental image of this. If it's a small group of people, they might look something like that. If it's a bigger group of people, maybe they look more like this. But if we go around to each of these people, we'll find they're sitting at their computers writing code. Now we'll repeat that thought experiment, but I'm going to replace software with silicon. What does this look like? This might not be as clear of a mental image. And even if it is, I suspect there's not quite as much of a consensus between you on those mental images. So I asked a bunch of people this. I get two common wrong answers. The first one looks something like this. Seems like everyone remembers this. It's Intel's Pentium ad campaign from the 90s, where eventually Casey and the Sunshine Band will break out, and these guys will start dancing. There they go. so this what we call fab job is a real line of work uh but not quite what i'm going to talk about i'm going to talk about the design of the content of these chips so not quite what these guys do now the second answer i often get is that people say well you must have some kind of elaborate and i'll often kind of gesticulate it with their hands like this you must have some 3d elaborate cad thing that you can manipulate and they describe something that looks kind of like what the future police can do in Minority Report, which is wrong, too, on a couple levels. One, there are no chip designers who look like Tom Cruise. Two, we don't have any other fancy software either. So this little experiment was more or less a trick question. Mostly, they look the same. This is code, too. In our case, it's just older and crappier. and i'm going to introduce what a lot of that code looks like how it works through another analogy to a set of things that you probably don't think about every day but know are there a sort of ladder of abstractions that you can build programs upon here at pycon most of us are working at kind of the top of this stack and what we'll call high level languages after a couple rungs in between which your program may or may not go through we know that they end up as instructions. Ultimately, this all boils down to machine instructions. They're the only thing that your processor knows how to execute. It's kind of a bedrock layer at which the software ends and the hardware begins. So what are those instructions? They're essentially an enumerated list of things that the processor knows how to do. So examples include those from x86. x86 is well known for being very confusing but they are kind enough to post a twitter account listing and describing the instructions such as well this one doesn't make a ton of sense floating point random manager uh complex multiply with rounding and conjugate signs makes even less sense to me and maybe this is becoming clear by now certainly will with this one rollback memory transaction to the last time any of this made any sense. This is really a parody account on how complicated and confusing x86 is with instructions such as stop brute forcing instructions that aren't in the manual. We mean it. We might change them. Okay, so the goal is not just to make fun of the x86 instruction set, but to point out this is this sort of bedrock layer for a piece of software. Where is that for our hardware designs? Is it maybe transistors? We haven't really talked about what those are, but we know they're really small. We know we make very, very many of them. Is it maybe electrons? Can we manipulate those one at a time? Not quite. Reality is it's somewhere in between. At the end of the day, my work product and really everyone's sort of hardware work product boils down to sort of a physical blueprint. Something like, at least conceptually like, this 3D image on screen. This is the physical design to be fabricated. That's what every piece of hardware has to resolve to. It's kind of what makes it hardware. Now, you may say I'm sort of going back on my Tom Cruise comment earlier. This looks sort of fancy. We would almost never look at it this way, though. What we would typically look at is a 2D view looking sort of down the z-axis at this that we'd call a layout, where the colors represent sort of depth in and out of the z-axis. you could imagine pairing with the figure at right being a cross-section describing what happens as you travel through z and the physical representation of this thing would almost always be used and manipulated and viewed via the 2d layout form on the left so those are sort of the instructions they're polygons okay that's that's what's at bottom of our stack now while there are people whose job is to manipulate these polygons day in and day out uh they're not that many of and obviously you can't get too far along the upping the complexity. So there's an analogous stack built on top of this as well with four, we'll see, relatively comparable layers. We looked at the physical layer first, and we're going to walk our way up to where the Python stuff is going to enter at the top. First, we're going to go through two more, and that's where some of the languages we use today are going to be introduced. So next layer up, which I'll call structural, is hardware being described as assemblies of other blocks of hardware and connections there between. Prominent example, this is the schematic of Raspberry Pi, which is a popular single board computer. This is actually not open source anymore. This is a version from 2014 that was open source. But each of these boxes represents some other piece of hardware, right? It might be a chip that you can buy. It might be another schematic somewhere. Lines represent connections between them. Now, in this structural region, we have a pretty big gap within our hardware community with roughly the system PCB level folks and analog silicon folks on one hand preferring these graphical schematics and our digital silicon folks on the other preferring something like what's on the right, code and text. The left is not particularly easy to see here, but it's a transistor level schematic for a chip. On the right is our first introduction to Verilog. And this is just instantiating a handful of logic gates, wiring up between them. Now, for this kind of content, you could imagine describing these things in a markup language, an XML, a YAML, something that just says what these objects sort of have, that doesn't have any means of executing or doing anything. Around the early 80s, we started to reach the complexity of designs that became difficult to handle that way. And this was kind of the heyday of the introduction of these hardware description languages, including the two that we still predominantly use today. Both of these are based in C. In fact, a lot of the Verilog syntax is actually compilable C. And Verilog today in 2019 is still the overwhelming leader VHDL relatively distant second. I'd like to point out 1984 is also the year I was born. 35 years later, despite not much evolution, I'm still here telling you Verilog, virtually every piece of digital silicon you use was written in Verilog. Now, what do these things do? In addition to that structural sort of wiring things up content, what they really added was the next layer up our ladder that we'll call behavioral. And that's a sort of suitcase term for a handful of features, which I'll use this excerpt of an open source RISC-V CPU to introduce, which does have a handful of these structural features, such as input ports and wires, but it also has some more programming language-y things. It's got for loops, and what's not going to be obvious syntax-wise is begin and end are essentially the curly braces of this language, and what happens between them are essentially functions that operate procedurally beginning to end. So the idea, the 35 years ago idea, was let's describe this hardware in something more like a C or C++ kind of description. Moreover, these functions don't have names. This always thing is a little bit more like an annotation or decorator that describes when this code should run. So, there are a couple of patterns built into these languages that have looked pretty weird over most of their lifetime, but have actually gotten relatively popular in a lot of really popular programming libraries today. We're going to look at three of them, reactive, event-driven, and asynchronous. The first one, the reactive pattern, is probably easiest to compare and contrast with the more common imperative model, which the two work identically for a block of code like this. If this is Python, which would be imperative, we set A to 1, B to 2, C to the sum of the two, the value of C is going to be, no surprise, 3. Where they start to differ, on the other hand, is if we have the same first three lines, but then after the assignment to C, we go and change A and B. All right, so this is a Python program. The value of C is, of course, going to remain three. If this is a reactive program, in contrast, C somehow behind the scenes finds out that A and or B changed and becomes 33. Now there are popular libraries doing that now. What's it got to do with hardware? It turns out it maps very cleanly onto hardware, so much so that Verilog, for example, as a keyword dedicated to making these reactive assignments. It's a sign. And it particularly models what we call combinational hardware. These are logic circuits where the outputs are solely a function of the current inputs. What does this look like as we sort of walk down our abstraction ladder? Well, this turns into just a couple of logic gates. And an even more common example, This is a circuit you've got at least a few million of in your pocket or hand or lap, half add or sell. Boils down to either two reactive assignments or two logic gates. Okay, pattern two, event-driven, is what I colloquially describe as stuff somewhere in the program happens and some code elsewhere in the program runs in response. to it. So this is common in, say, a web environment where the stuff happening we would call events, they might be in the form of user actions, they might be in the form of disk activity or network activity completing, and then the stuff running in response is usually in the form of functions. Correspondingly, in the Harvard description languages, the code running in response is still these sort of functions. We call them procedural blocks. The stuff happening tends to be the state of the system somewhere else changing, usually a signal. And this is very common for a couple more terms we'll introduce. Sequential logic is essentially circuits that have state. And the very common synchronous logic, which is having the idea of having this sort of global heartbeat signal that synchronizes all the activity that we usually call a clock. So making a state machine out of this, and this is a very typical intro to a Verilog FSM example, which says the annotation at top says every time the clock ticks, start running this function. Everything between here runs beginning to end based on the inputs, figures out what the next state is going to be, what the outputs are going to be. Okay, third and probably most prominent within Python and JavaScript and a couple of places is async. So this is an idea risen to a lot of prominence through libraries like Python's async.io that we're going to have function-like things that we'll add a little bit of syntax onto such that they can sort of pause execution, defer to some other part of the program, maybe the calling context or even elsewhere, and declare when they would like to resume. So in this case, we declare two of these async functions in which the execution jumps from one to the other based on a sleep statement, continues in the second, and then goes back to the first. And if we run this, we get the order of events we expect, steps 1a and 1b, which I'm not sure if async.io deterministically would set 1a and 1b to always go in that order, may or may not, but certainly the two 1s, then 2, then 3. Particular HTMLs, Verilog for example, have actually had this idea of delay kind of coroutines built in that it's not even a keyword, it's just a key character. That pound hashtag character is essentially wait so long and then come back to me. And if we run something like this, which is a very similar thing of print these same steps to the console, read the same order. Initial, in this case, I'll note, most of these functions are sort of anonymous. Initial just is more of an annotation of when it should run. That one in particular meaning run at the beginning as the thing is waking up. And what I mean when I say run, the common question I get is, you know, wait, if you have these functions, they're anonymous, how does anything call them? When does any of this code actually run? This tends to be one of the more confusing ideas because the languages are really designed for at least two primary runtimes. One we call logic synthesis. This is essentially the compiler. This would be the thing that did the conversion into the logic gates we saw earlier. The other is simulation, which is for sort of predicting the behavior. Now, what is particularly confusing, and I find is consistently aggravating to people coming to these things, is that these things don't run in sequence. It's not compile and then run. They run separately, which means there are a lot of programs that run but don't compile. In fact, the compiler is usually the more stringent of the two. Okay, so we have these cute analogies to some of these modern asynchronous tactics. That's cute, but really these things are based on C. They're not great. What can we do about this? Some coping mechanisms. I'll quit. You know, go do something else. Not a terribly uncommon approach. We'll talk about templating, which is certainly not unfamiliar to anyone in the Python web space. And we'll talk about more drastic things like generating code or placing language altogether. Templating is this idea that, certainly if you are users of Django or Flask, most Python web frameworks, that you're tasked with delivering this big bunch of some crappy language, let's say HTML or Verilog. And you also have some nicer language, like, say, Python. And so the idea is we'll take the crappy language and we'll find a way to wedge the good language into it. And then we'll run some kind of expansion program that turns our very productive, nice, good language into this pile of very verbose, crappy language. So this is the example on screen using Jinja. We really kind of have three languages here, right? There's the good, the crappy, and the sort of syntax for embedding the two, the Jinja template syntax. and that works. It's not totally foreign to us. We've been doing it with Verilog and company for many years. In fact, it's probably where most Verilog comes from, to be honest. The most common templating is not great. It's sadly Emacs templates, but we at least know it's there. I'll note a contrasting approach. What I tend to think of as kind of the inverse of this good language, bad language arrangement is what JSX does in the React JavaScript library, which is essentially take a subset of the ugly, crappy language, XML or HTML, and bring it into JavaScript, the good one. Whatever you think about JavaScript, it does have a lot of the good features, like define classes at runtime. This is making something akin to a class decorator that takes one class, manipulates it, and inline defines and returns another one. So that I find quite effective. Nonetheless, all of these kind of templating, gluing these different languages together, things are sort of band-aids. So we get to our top-level rung on our ladder, this high-level hardware description. And we haven't really reached much of a consensus in our part of our space about how to do that. There are probably two most common approaches, one that we'll talk about much less. As a family of tools that we generally call high-level synthesis, the idea here is to throw out all of these hardware abstractions that we've talked about, ports and signals and blocks, and instead write a relatively low-level software program, say in C++ or C, and have a very elaborate compiler transform that into the hardware abstractions. That has some domain of applicability, things like the MATLAB translation we heard about in the last presentation could be cited as an example. There are even more elaborate ones. There are also large domains where I've never even heard it being tried. It just doesn't tend to work at all. What we are going to talk about and where the Python is going to come in is a newer contrasting approach, a family of things that we're going to call modern HDLs. Now, these are a set of tools that have a couple of traits in common. Instead of defining a new language altogether, they're built on top of some high-level software language, Python and a few others we'll look at, and you find a domain-specific library on top of So this generally includes the list of hardware concepts that we've talked about here, such as the block or circuit or module, and the signal and port, input and output. They almost all don't care for this high-level synthesis idea. And in fact, many, or probably even most, don't use the event-driven paradigm either. What they do instead is use the programming facility and the productivity of the high-level software language to manipulate something more like that structural description we looked at with the schematics and the wired-up Verilog. A lot of them are from academia. And the most accomplished of these is not based in Python, sorry, is Chisel, written at UC Berkeley, which is based in Scala. If you're not Scala programmers, it's a strongly typed, newer-ish Java virtual machine language. Chisel uses an analogy we'll see in a lot of cases, which is each block of hardware is a class, particularly a subclass of something defined behind the scenes called module. The Scala syntax is such that the body of this class is the constructor function. So this example is defining everything in the constructor function. It has a lot of the same constructions we've looked at throughout this talk with the older HDLs, such as control flow sort of bolted on for these logical statements. Reactive assignments are overloaded operators. now chisel is definitely been used quite widely in academic tame outs there's at least a few dozen of these and it's also uh gotten some commercial deployment by plucky little startup companies like google uh they recently did a talk on using it in a chip called their edge tpu this is kind of an IoT-grade machine learning inference accelerator, which I'd recommend checking out. Now, it's hard to say who's kind of in second amongst this survey of these modern hardware libraries. Certainly a contender is SpinalHDL, which is also not Python. It's also Scala. Looks very similar syntactically to Chisel. Definitely also been used quite a bit in the academic space. Same analogy, piece of hardware is a class. A lot of the content is defined through the constructor. But I know what you're thinking. It's not ScalaCon. It's certainly not VerilogCon. Where is the Python here? We've got quite a few such Python libraries that we're going to do a little survey of. The first, which we saw in our last talk, kind of the original, is MyHDL. This is notable in that it's one of the few, and I think the only one we'll look at that maintains this event-driven paradigm. It does so with a means of constructing a piece of hardware that I find a bit counterintuitive. A block is essentially a function decorated with this block decorator, which essentially returns its content. So in this case, it's defining a few decorators, which mimic that sort of annotation of when to run behavior we looked at in the dedicated HDLs, like always, and defines a few inline closures of what's going to happen in those functions and returns those. Now, if this had some more elaborate content, if it had instances of other pieces of hardware, for example, it would return those as well. MyHDL is bringing to the party all of these ideas like block and signal, all of kind of the base layer hardware abstractions. Second, Mijin and NMijin are a small family that have got some usage. They also use the each block as a class idea and largely defined through the constructor as well. The thing I really wanted to point out with these is the utility of Python for another related and often fairly painful function, which is testing of these things. So generally writing Verilog, testing Verilog requires writing another piece of Verilog test bench code. that can be pretty difficult to write and exercise the entirety of a piece of code that has a bunch of internal state. It has a bunch of behavior that operates either in parallel or concurrently. And what Mijin and a few of these other libraries do is use generators, use yield, and I think in newer versions, await as well, to mimic this sort of control flow back and forth between the test code that you define and the sort of runtime that allows the hardware model to execute. Third, we're going to look at Magma. This is written at Stanford. This is the one that probably uses the most Python metamagic behind the scenes, largely to define a lot of the stuff at the class level and then manipulate it around into every instance. you'll see again that we use the every circuit as a class or subclass analogy these things are defined at the class level more directly so in this case we're making a sort of ripple adder putting a handful of adder cells in sort of a series parallel combination wiring them up through the content of this definition method And Pymetal at Cornell is a little bit more purpose-driven for their computer architecture research. So has a few more things baked in to fulfill those purposes rather than for the sort of general silicon design process. Also uses the block as a class analogy. also largely defined in the constructor a lot of what you generally see looking at a lot of these is a lot of these classes just have a constructor function now you might be looking at this and saying wait i see some other functions here what do you mean there's just a constructor but they aren't other functions they're closures they're closures that are defined inside the constructor and that's particularly because the annotations, the decorators, are methods on self. So somewhere that has access to self is kind of a more convenient place to define these things. Same event-driven paradigm applies here with a little bit less flexibility about what the events are. So something like tick is essentially always at clock. Combinational is like the reactive assignments that essentially say s.out is forever equal to the value of regout plus one. So having looked at these Python libraries, I'll note another example not based in Python. That's a very different take and highlights that there's a lot of ways to skin this cat. This is called Clash. This is based in Haskell. I don't know Haskell. I only know two things about Haskell, in fact. One is that it's a strictly functional language. Do we have any Haskell programmers in here? Zero. Okay, great. We're all in it together. It's a strictly functional language is the first thing I know. The second is that when I look at the syntax, it makes me think, I don't want to know Haskell. And it also confuses me. it is hard for me to understand why you'd want to use functional programming for this. Now, I revealed my age earlier, so maybe I'm a little too old to realize that functional programming is both the best and most important idea in world history. But it certainly maps pretty poorly to my eye onto this hardware definition process. The combination of state and behavior that we would usually encapsulate into a class fits that analogy a lot more closely in my mind. Nonetheless, just pointing out many ways to go about this. Okay, so ends our tour of these libraries. Why care? Should you care? Not everyone is going to, beyond sort of academic interest in this, but there are some increasing reasons to. And the general trend, there are a couple of general trends dictating this. The first one that I'm sure you hear about is that we're not getting this free lunch as far as performance increases year after year after year going forward. I've always disliked the term Moore's law, but we're not just going to get the process technology speeding up generation after generation permanently into the future. And we've already seen it sort of peter out. So what you see more and more of, and I expect in the coming years, you're going to see even more custom hardware design than you have in past years, are for compute intensive things, these accelerators. So big companies have a whole bunch of versions of this that are either integrated in SOCs and essentially every mobile SOC, or in dedicated form in a server room somewhere, such as Google's tensor processors. And a sort of special category of these, which we heard extensively about in the last talk, are FPGAs, which are what we call reconfigurable hardware, generally programmed in the kinds of hardware description languages we talked about here. I should also note on the accelerator front, There's just a litany of startups making these things, particularly with the primary use case being, of course, machine learning. Now, if you don't care about these accelerators or performance things, there's still reason to care about all of this, which is there's another material shift, which is the rise of RISC-V. RISC-V is an open source instruction set, also developed at UC Berkeley, really rising in prominence over the last couple of years. There are quite a few very nice open source processor implementations, as well as closed source proprietary ones. And if you believe that projects like Python are made better by being open, and that it would be a good thing to have at least some form of a compute stack that's open all the way down, then this is a positive development. There are quite a few other nodes in that stack to be filled. But a very helpful, very good development. What I want you to take away. Above all, really my sort of one-line message is we've said a lot of stuff, but really it's that we've erected these two sort of silos, software and hardware, and sort of from the start treat them as being very different. And my message is a lot of that's artificial. They're not so different after all. especially once you recognize a lot of these similarities we've talked about here. And so custom hardware is getting increasingly doable. These trends are reason both why it matters and why it's becoming more accessible, right? This sort of convergence of these paradigms and the rise of these libraries and open source architectures. And let's face it, we can apply software to all kinds of domains. You can apply it to finance or recommending movies. Face it, this is pretty cool as compared to those things. If you're in engineering, you know what it is. So I write about this stuff in more depth on a Medium publication, Software Makes Hardware, link there. And if you're interested, this is covered in some more depth. And I'll be happy to take your questions. Hi, thanks for the interesting talk. uh forgive the very beginner question there you showed some code examples how am i to understand those examples like the hello world uh examples from uh yeah one of maybe it's that one yeah how does that translate in into hardware what do i get from that what what yeah so this is a good question that kind of boils down to that counterintuitive thing i described where there are sort of two runtimes for these hardware languages the simulated one which essentially captures the behavior and the sort of compiled one that turns it down the stack towards either gates or physical layout and things like print obviously don't get synthesized down to gates right there's no console to print to on an eventual chip so these fall in the category of things that we call non-synthesizable that only kind of work in simulation now that category is perhaps broader than you would expect it includes things like this but also a lot of what might seem like valid but aren't quite hardware modeling constructs but this is uh really generating a clock and printing to the console so hello worlds is you know not much more complicated than your regular program hello worlds here um hi thank you for the interesting talk um kind of a noob question uh how shall we think about the computational model that this represents or what is the big difficulty here. So a normal language is set to run on a computer that runs instructions one by one. And then you have event for the web or async for parallel processing. What kind of model is at the bottom of this? And can you describe it in a simple way? Yeah, good question. So what's really different and weird about these languages is their model of concurrency and parallelism, right? The hardware is inherently parallel. There's a whole bunch of things sitting within it that you're describing that are sort of always running all the time in parallel. And the languages use concurrency to essentially emulate that parallelism. At bottom of one of those runtimes, the one that I've probably mostly referred to here, the simulation runtime, is that event-driven paradigm. So how that operates is the system is essentially generating a sequence of events sort of for itself, expanding on that. Signal changes, there's some behavior tied to that, maybe some logic tied to it that generates changes in another signal, and then there's some annotation that says anytime signal B changes, please do this other stuff again. So the event-driven is kind of the primary simulation paradigm. There are simpler ones, for sure, and faster ones than that. But the languages are really designed with that event-driven model in mind. Thank you for a talk from another planet. Can you believe I have also a question? How do you know what to program? What comes first? Like, how do you get the task to program? Like, what kind of program to write? Yeah, good question. I mean, how do you do that, if you can hang on to the mic, how do you do that for a piece of software? For example, from Jira? From Jira tells you? This is another place where my analogy of these two jobs don't look very different continues to hold, right? So there's no magic. There's no, like, you know, handed down from on high, here's what kind of hardware an individual person or company or the industry should make. There's some collaborative process, just like with any piece of software, about a combination of what's feasible, what's attractive, what's useful, what we can do on what schedule, how many people it's going to take, what kind of skill sets do we have, et cetera. So the kind of stuff I've shown here, I'll keep in mind, this is really for the design of custom hardware at pretty close to every level. So by level, I mean PCBs, PCB-level systems, and I particularly mean chips. So whereas in the last talk, we talked about sort of FPGA programming, doing this reconfiguring of hardware, what the stuff we're talking about here is the designing that FPGA or designing that GPU in the first place. I'd like building on that question. So is it that you have mostly, most of your work is built, you start from a template, or you're kind of fine-tuning a pre-existing one? Like you take an open-source one and then you configure that for your own purpose? Or how often do you start from scratch? Yeah, good question. So, let's say the role of open source is very different. The prominence is quite a ways less in our hardware space than it is in software. And we can sort of deconstruct the history of why that is, but just looking at the reality today, whereas most popular software, let's call them products, get built with a bunch of open source underneath the hood, there really aren't those layers sitting around available to design a chip. And there are efforts that are underway. The U.S. government actually has a pretty significant one to try to change that fact. But it hasn't really materialized on its own as it has in the software space. So framing more onto your question of do you start from scratch or do you start from something existing, It's usually inside of companies that you're starting from something existing, right? It's, there aren't a ton of companies doing this stuff, although there are an increasing number, and particularly the large software companies have increasingly gotten into it. There's generally within these places sort of a library of everything we've built before to start from, and much less of the what's out there in the public domain to start from. Hi, thanks for your talk. my question is the htl stuff is used for defining the logic of the chip but the next part would to realize this chip the chip by placement routing and so on is there a python solution for it or is python used for it or is it already a c assembler and so stuff as 10 years before yeah great question too so this is another Another pretty significant hole in sort of the open source community for this space is what we call EDA, electronic design automation, essentially the tooling for doing all of this stuff, the runtime for the simulation, the compiler, all that. each of those things do have open source versions. Unlike with, say, Clang and GCC, the open source versions generally lag behind commercially available, very expensive alternatives. And the difference is sufficiently significant that playing at the high end really requires the very expensive stuff. And that's for a couple of reasons. One is there's not as much supply of people to contribute to those things. Another is they are oftentimes awfully compute-intensive. I don't know of a synthesis engine that is certainly written in Python. Maybe at best you could have an interface to what would typically be C and C++ written. I'll also note that part of why a lot of this is in C and C++ is it's just not that new. right there's you know if we were at verilog con or eda con instead of pycon it'd be a much sort of sadder duller affair than this there's just not as much action uh so short answer is not that i know of thanks a lot