 All right, without any further ado, I would like to introduce Charles Papon, who is the main developer behind Spinal HDL, a hardware description language which you can use to program FPGAs and the like. He is working on Spinal HDL full-time, and I'm looking forward to the presentation. Please give a warm round of applause for Charles. Thank you. So during this talk, I will start to tell you a little bit about why VHDL and Verilog are not so good. Then I will introduce you Spinal HDL, and all the rest of the presentation will be about showing you an example and thinking about why this is better by the way the example are done. So yeah, as said before, this presentation will only be about synthesizable hardware. I will not talk about any simulation features or these kind of things. So yeah, VHDL and Verilog were initially designed for simulation and documentation purpose, and it's only later that they were adopted as an input language for synthesis tool. And that was a very long time ago, which means VHDL and Verilog miss many features that could be interesting. And to infer hardware, you have to use simulation constructs like process and always block, which doesn't really make any sense from a RTL point of view. Although you don't have things like object oriented programming and functional programming, it could send strings to talk about object oriented for synthesizable hardware. But in fact, it make a lot of sense. And I will show you some example where it is really powerful. Then in VHDL and Verilog, simple concepts are often very verbal, like instantiating a subcomponent or a submodule is very painful. Although you don't have some notion of interface, you are always immerting signals one by one. And many of the things that make them not so good and you don't have possibilities to rise the absorption level. If you use VHDL and Verilog, you will be still stuck in kind of wire abstraction layer. You would still have to connect everything by hand. You will still have to define gates one by one. I mean, it could be better. Then there is VHDL 2008 and system Verilog. But yeah, they are not really there to save us. I mean, they still keep the same wrong paradigm to infer hardware. You still have to use simulation constructs. You are still using the event-driven paradigm to infer the detail. Then they still didn't offer any meta-hardware description capabilities. And the idea tool supports could be very bad. I mean, there is many interesting features in both language, but depending the idea tools that you have to use for simulation or for synthesis, you will not be able to use them, which mean, yeah, you are still stuck in a subset of them. And as well as instance, system Verilog were very interesting features, which is interface definitions. But we will see in this tool that even these features is not that good with system Verilog. So yeah, what to do next? My solution, and it has a solution of other people. One solution is to use Verilog Verilog as netlist language, which is automatically generated from a higher level language. And there I go with Spinal Agil. So basically, it is an open source project that I started in December 2014. It's focused exclusively on RTL description. So the idea behind that is to not do any compromise, to really have the best language possible, to do one very precise things, which is describing RTL. Then since the beginning, it was seemed to be interoperable with existing tools, because you can go to the Xilinx company and ask them to support your brand new language. They will never do that. So the Spinal Agil compiler is able to generate its output netlist as Verilog or as Verilog. You can also integrate legacy IPs inside the Spinal Agil hierarchy by using a black boxing system. It's a little bit like having a C header file. Then the abstraction level starts at the same level than VHDL and Verilog, or nearly the same level. But the thing is, on the top of Spinal Agil, you can build new abstraction level. You can build new tools, and it is its biggest powerful side. Then there is the flow. So basically, you will have to define your digital description by using the Scala files in Spinal Agil. Then you will ask the Spinal Agil tool to generate the corresponding Verilog netlist. Then you can grab your Verilog IPs and put them all together. And you can use your flow as before by using same simulation tools than before, and same synthesis tool than before. So yeah, now I will start with some examples, just some things that's points to talk to you. So Spinal Agil will not create any overhead in the generated RTL. You will not lose gates. You will not lose performance, because it is not kind of issue-less tools. For example, there is Vivado Achilles, where you write some, not arbitrary, but you can write some C algorithm that will be translated automatically into RTL. So Spinal Agil is not that. Spinal Agil is really an RTL approach where you will have to define register a little bit as before and gates a little bit as before. Then all components here key and all signal names that you define Spinal Agil are preserved in the generated RTL, which means you can do your simulation as before with the wave. You can look signals and match them with your Spinal Agil description. It's not an issue at all. And OK, Spinal Agil, in fact, is not really a language. It's what we call an internal DSL. So Spinal Agil is basically a scalar, which is a scalar library. So a scalar is a general purpose language, and Spinal Agil is a library implemented on the top of it. And it could seem strange to have some language into another one. But in fact, this is probably one of the best part of Spinal Agil. So example. Yeah, there is a simple example where you have some common conditions to drive a max, to drive a counter, to drive another counter with a reset value. In VHDL, you would have to, if you want to do that, you would have to write three different processes because you are in an event-driven paradigm. And yeah, this is how you have to do things. It is really boring. It is really variable. And as you can see here, you duplicate three times the same condition, which is not very good in terms of code quality. And there is a equivalence in Spinal Agil. So first, to define signals, it's already different. Then if you want to define these combinatorial signals, you just say, I want a bull, which is a hardware bullion data type. Then if you want this register, you say, I want a reg of this given data type, which is inside of probits. So it's not like in VHDL and Verilog, where a signal has become a register because you assign it in a clock process. So it's not that. Here, it's really explicit at definition. And this simple fact changes a lot of things. Like, for example, you can assign all those guys inside the same if condition. It is a random example. But basically, it happens very often like in a state machine, where you have a combinatorial path. And a second shell part, you have to duplicate three statements. And this is terrible in terms of code quality. Then for 28 line of VHDL before to 9 line of Spinal Agil with a better code expressivity, it's good. Let's take another example. Let's imagine you have an RGB color input and you want to calculate the gray level of those inputs by multiplying each of them with a constant coefficient. So here, I can see that I have three times the same pattern. Basically, you have three times signals, unsigned signals, and a floating point constant. And then as output, you get the output of a register. So you have three times this pattern. If you want to be smart in VHDL and avoiding rewriting each time the same, three times the same stuff, you can define a component, which content that. But using component in VHDL is really boring. It is very verbose. So it's not so good. But here, you can use functions. So let's take the Spinal Agil implementation. So for example, here, we can define an RGB value. Then you can define a function, which takes as argument hardware unsigned value with an elaboration time floating point constant. And this function will return you the output of this flip-flop. So you can see, for example, defining intermediate register as a reg of 8 bits, then doing some fixed point calculation and returning it. And then reusing this function multiple time. So yeah, in VHDL and VHDL, you have functions. You have procedure. You have task. But you can't instantiate in those function arbitrary hardware. You are still kind of stuck with a syntax that will limit you to give relationship between inputs and outputs, but in a purely combinatorial way, which is not very powerful. Then yeah, let's take another example. Let's imagine you have a handshake bus. So a very simple bus with just a valid as master abstraction and are ready from slave to say, stop. I'm not ready. Or yeah, you can go, I'm ready. And a payload. So as you can see here. And imagine you have two instance of this bus, like source as in sync. And you want to insert a queue between those buses. If you want to do that in VHDL, you will have to write all this boring stuff. So like redefining all signals one by one of your handshake bus two times. And you will have also to instantiate the 5-4, which is yeah, it is boring. I mean, you have to map, for example, into a single delegate vector. All those guys, one by one. So here, we just have three elements. But I work in the company where in other ways, we have like 20 signals each time to map into those data structures. So yeah, it's not very great. Then here, there is a first approach of how you can do that in Spinal Agile. So in Spinal Agile, a handshake bus is named Stream. So a stream is a handshake bus that can carry an arbitrary data type. And here, it is an RGB color with this parametrization. So here, it can define source and sync, which are stream of RGB color of this parametrization. Then you can define a 5-4, like a 5-4, a stream 5-4, which will carry this kind of data type with this depth. And here, you don't have to bind each signals one by one. You even don't need to bind things. Basically, you can directly access IO of this 5-4 by saying 5-4.io.push, for example, to access TSPAR or POP to access TSPAR. And here, for example, it's saying, I want to take my source stream, and I want to connect it by using a fully asynchronous way, though direct connections in respect of signal direction to the 5-4 IO push part. And then here, you say, I take the 5-4 IO POP part, and I want to connect it to my sync. So the fall from 29 line of the LGL to 7 line of Spinal LGL, it is good, but it could be better. Later, we see a better way. Then, OK. So here, we've seen that we have an RGB data structure. It comes from the Spinal LGL library. And there is how it is defined. Like it is a case class, which is a case class named RGB with this parameterization for the construction of it. This class, extend bundle, bundle represents the notion of data structure in hardware. Then here, you can define elements that you have in this data structure, though it is simple syntax. And for example, here is the definition of the stream concept in Spinal LGL. So this is still a case class, which take as construction parameter data type. Then it takes an a bundle. It still represents a data structure with the concept of master slave, because you can take the stream and say it is a master part of my component or a slave part of my component. Then can define the valid, the ready has Boolean signals. Then the payload as an instance of this parameterizable data type. Then you can implement the as master function to say how this data structure could be set as a master or the slave of a component by saying, as output, you have the valid and the payload. As input, you have the ready. And then you can already do this kind of syntax. And here comes the fun stuff. So basically, I told you before that Spinal LGL is basically a scalar library, which means here, this is object-oriented stuff, which means you can add function in this class. Like adding the combinatorial operator connection and the reverse one, which means the reverse of this one. And you can also, for example, add in this buses definition a function that will, when you call it on a stream, it will insert a 5.0, connect this stream on the one you are calling it, connect it to the push port of this 3, of this 5.0, and then returning the pop port of this 5.0. And there you go. You pass, you are moving from this code as before, which will do everything by hand in Spinal LGL. To this code, which is only two lines, like where you say, I have a source and a sink, which are a stream of RGB color with this parameterization. Then I take my source. I want to queue it with a 5.0, a 16 element. And then I want to connect the output part of this 5.0 to my sink. And yeah, here we start to try the level of absorption via going out of this mess of wire, which is a hardware description thing. So this is a simple example. And there is many other funny things that you can do with streams. Like, for example, imagine you want to do this arbitrary hardware. Like, you have a stream of color. Then you want to drop transaction of this stream of color when they are black by adding this arbitration. And then you want to add a pipelining stages for performance reasons, to cut commercial pass. I don't know. If you want to do that, if you want to do that in VLGL, I don't know, it is really boring. If you want to do that in Spinal LGL, it's only two lines, like you say I have a stream of RGB color, named source. Then you say, I take the source. And I want to throw its transaction when the source payload is black. And then I want to add a pipelining stages at the end of it. And then I will name the return of tstaging function sink. So all this stuff here is infrared by just this line. Because, for example, here in the RGB as a structure, we also define s black function and these kind of things. So it could look like magic, but in fact, it is pure RTL. Because if you look like how is implemented the throw-in function, you will fall on something which is pure RTL. I mean, Spinal LGL is not about adding magic things that will make abstraction for you. You can always look inside how it is done by using regular RTL. Like the throw-in function, where you can see its instantiate our return stream of the same data type. Then by default, it will connect tstream to the return stream. But it will infer those gates there on the valid and the ready by adding some additional conditions. Like if I want to throw transactions, then put the valid to false. And then I will put the rigid true. I mean, yeah, this is still regular RTL. So, yeah, now I will change the topic. Safety first. I mean, when you do RTL, it's very easy to do bad things like inferring common-tall loops across multiple modules, inferring, for example, some latches by forgetting assigning a common-tall signal in all case. And Spinal LGL will check all those crap things for you. So, for example, this loop will be detected by Spinal LGL compiler. Or here, the result is not assigned by default if con is false, which will infer a latch. So, which means if you successfully generate, if Spinal LGL generates you the output RTL, you have much more trust in this generated RTL than in a handwritten one. Because many, many things are already checked for you. There is also some checks about clubdom and crossing, which is done. Then basic abstraction. So, yeah, it is a simple example of what could be abstract. Like, imagine you need to do a communication module and you need a timeout inside it to check some things. You can say, I want to create a timeout named timeout, which is a timeout which will take after 1,000 cycles. And then you can say, if my timeout tick, then I want to clear it. But it is hardware. But as you can see here, we are using a function to access our hardware. In place of saying timeout.counter equals 0, I use a function named clear to infer it. Another example is if you want a counter, which would come from 0 to 9. You can say, I want a counter of 10 states. Then you can say, I want to clear it. I want to increment it. I want to get its value. I want to get its next value. I want to know if it will overflow this cycle. I want to check if it's a goal to 5. I mean, these kind of things, you can kind of have them with the algorithm very like by using components. And you know how components are boring to use. And here, you just say, you want it. And then you can use what you want. Then, oh, yeah, just those abstractions are built on the top of Spinal Agile. It's not something integrated in its compiler, which means you can create those abstractions. You can define what is a timeout or these kind of things. So functional programming, basically functional programming is something which is big. And here, it is one part of it, an example of just one part of it. Like, if you want to infer this hardware where you have an array of addresses, then you want to check which addresses are equal to a given k. And then you want to know if one of them is true, though you want to do that. You can say, I want to define address, which is a vector of t-zeta type four time. Then you can define the k. And then you can say, I take my array of addresses. And I want to create a new array from it. So you use the concept of mapping. And you give as a transformation function that you want to translate those elements one by one to the next array. You can also use the reduce concept of functional programming. Like I say, I take its array. And I want to reduce it to a single element by using this reduction function, which will be used on each element or each pair of elements to reduce them until a single one. So it's kind of things that you can use very easily with Spinal HDL. And yeah, this is a funny thing. Basically, each time you use Spinal HDL, in fact, you are doing some scalar programming by using Spinal HDL library. And basically, each time you use it, it will build into your computer memory a graph of your design, which means you can also ask how this graph is currently to get some information of it. Imagine you have A and B, which are both values, the current together, which are both together. Then you have A, which go through the calculation pipeline that you don't really know the latency. And then when the result of A come out, you need to add the B value that were present at the same moment than the A were present there. So you have to delay B by the same delay than this pipeline. And basically, in the HDL, our failure to do that, to know how many cycles you have to use to specify for this gift register, you will have to come by hand, maybe. Or you will have to run simulations to look at the wave and these kind of things, but it's not very nice because if the pipeline latency changes, you are kind of annoying because you have to change things and maybe you will forget, you will create bugs. Yeah. But in Spinal HDL, you can, for example, ask the netlist to give you the latency between this point and this point by using the latency analysis function. And there you go, the latency of this pipeline. And you can instantiate your delay with the right delay. I mean, which make your design much more elastic, which allow you to modify things there without having to care about this stuff. So I add another example. So this is more about what I mean is meta-hardware description, like stopping doing RTL with each time signals and these kind of things. So imagine you want to define a T-state machine with three states, state E, state B, state C, with some conditions there. Like when you enter in the state B, you set a counter to zero. Each cycle you are in B, you increment it. And on exit of it, you want to put a result to true. To do that, to do RT-state machine, you can do that in Spinal HDL. So you can use a state machine tool, which is, again, one thing which is implemented on the top of it. It's not implemented into the Spinal HDL compiler. So you can say, I want a new state machine. I want to define state A, B, C, which are states. And A is by entry point. Then you can define some signals and some stuff like that. And then you can say, on state B, on entry, I want to set my counter to zero. When state B is active, I want to increment my counter each cycle. And I want to check if my counter is equal to four. Then I want to go to state C. And on exit of state B, I want to put my IO result to true. I mean, this is really something to show you that Spinal HDL is not a fixed syntax. You can extend it. You can create new abstraction of the top of it. Depending on your challenges, it could be really useful. Then let's take another example. Imagine you have designed a timer, a simple timer with a simple tick input, a simple clear input, a limit to say when your timer will become full. An output value which will tell you when the timer is full and a value to get the current value of the timer. So there is a corresponding implementation of Spinal HDL of this component. Like you define a timer with some parameter relation, like how many bits you want for it. This class extend component to say, yeah, it is component. Then you can define IO of this component in a new data structure by saying you have ticks, which is our input, clear, which is our input bool, and yeah, simple things. Then you can define counter. You can define some variable of your component. And then, OK, you have it. You are happy. And you want to map it into something already existing. You want to, from a memory bus like the happy bit one, you want to be able to set the IO limit of the timer. You want to be able to define which external ticks signals will be able to make your time a tick, these kind of things. To do that, in Spinal HDL and Verilog, you will probably use some switch statements and these kind of things. But here, there is another solution, which is really using object-related programming. So basically, there is a tool named BusLayFactory. And this tool is abstract, which means it is an abstract class. And it defines how it defines functions that will allow you to define the mapping between a memory bus and some register of your design. And there is multiple implementation of these tools, like an happy bit tree one, a Navalan one, and an axi-light one. And there you go. OK. So as instance, in our timer component, in the bundle data structure with defined IO, we can add a new function that could be used to say, I want to derive this timer component from a memory bus, so BusLayFactory, at a given base address in the mapping of this bus. And you can also specify a list of signals which could be able to make your time a tick, can also give a list of clear signals to say that they can clear it. And then you can say, I want my bus controller to be able to drive and read the IO limit of my timer at the base address plus 0. So basically, yeah, here, you are saying that the IO limit is our register of this BusLayFactory. You can access it as a 0. And your bus will be able to read it, but it will also take the control of it. It will be able to drive it. Then you can say, you want to be able to set the clear flag of the timer when the bus controller is writing the base address plus 0. So I mean, this kind of abstract definition of our register mapping allow you to not care about the bus timings. Like you don't need to know the APB bus timings, or the Avalon bus timing, or the ACI for bus timing. You don't have to know how the bus work to create a custom peripheral, which is very interesting, because it means this function is abstract. You can use it with an Avalon bus and an APB bus without having to create a kind of bridge by yourself to map into a fixed definition. And there you go. There is an example how you can use all that stuff. Imagine you want to create a big timer component with a press color, with one 32-bit timer, and these kind of things. So you can define, for example, an APB 3 bus with this parameter section. Then you can define some signals. Then you can say, I want a press color of 16 bits. I want a timer A of 32 bits. I want a timer B and C of 16 bits. Then you say, you want to create an APB 3 bus slave factory, which will be able to map the APB 3 bus defined there to some hardware. And then you can say, for example, I take my timer C. I want to be able to drive IO of this timer C with my bus controller at this address in the mapping. And there is a list of signals that could be able to make it tick. And there is a list of signals that could be able to make it clear. So yeah, it is very short. I mean, it is really expressive. You say, I want that, I want that, I want that. I want to connect them like this way. And this is done for you. You don't have to play with wire by hand and adding logic by hand and all these things. It is very flexible. And if you want to edit it, you can't introduce a bug inside it. I mean, you don't have to play with timings. You don't have to play with all those things. Then yeah, it is a project which was made with PinellasDL, which is kind of a little macro controller with a RISC5 CPU, with instruction cache, with multiplication, division, extension, and this kind of things, with AGITAC tape to debug it by using breakpoint. And things like that. There is an SDRM controller for external memory. There is on-heap RAM. There is an ACI for crossbar to connect all those guys together with a good bandwidth. There is an IPv3 bridge to go to peripherals, which are GPIO, timer, UART, or VDA controller. And basically, there is some things which are interesting is the implementation of this design as instance, the IPv decoder. So for example, to instantiate this guy, though it is used, for example, five lines. So but I've already talked about these kind of things before. But for example, to instantiate this guy and create all those connections between them and also to define the mapping of all those guys in this arbitration. This is used that. Like you say, I want an IPv3 decoder. The master is the IPv bridge IORPB, so this guy. And there you can give a list of slaves, like the UART controller IORPB will be mapped at this address with this memory range. Then another example is how this thing is made. So the Axifa crossbar, which connect all those guys together. So here it uses build a pattern from object-oriented world. So basically, you can say, I want to create an Axifa crossbar factory. And then you will kind of feed a data model in this tool to say what you want. And when you have feed this tool with what you want, you say, it's all right. You can build yourself. And the tool will do what you want. Then as an example, it is tool have feeds a list of slaves, like saying, have the RAM, have the SD RAM, have an IPv3 bridge mapped at the total location. Then you can say, there is, for example, VGA controller, which should be able to access the SD RAM controller IOREXE. And this kind of things. And yeah, it nearly has easy than to use VivaDos things or Q-SYS things. But it's still pure code. It's without using graphical GUI. Then, yeah, about Scala. Basically, Scala is probably a very good general purpose language. Then if you want to test it, there is already some Scala idea which can help you to have syntax error, highlighting, refactoring, these kind of things, navigation tools, which are very useful. There is also an eMac plugin. And yeah. So about SpineHDL, it is, as I said, completely open source. You can find some online documentation there. There is some ready-to-use project with some directive how you can install tools and these kind of things. So yeah, if you want to try it, SpineHDL really goes there. There is also some communication channel if you have questions, like a GitHub chat. Do not hesitate to make GitHub issue if the compiler has some strange things. It could happen. But it is pretty stable now. And if you want to talk me in private, there is my email address there. So thank you. Thank you very much. We have some time left for questions and answers. If you want to leave the room now, that's OK. But please be quiet and take some trash with you if possible. In order to ask a question, please line up at any of the microphones, and I will call you out. Yes, please. Hello, thanks for your talk. I was wondering. So now we have this very high-level description of our hardware. So what is the debugging story like? So if something goes wrong, do we have to look at the VHDL code, or is there some kind of high-level debugging mode that I can use? OK, so for instance, I can take an example. So for example, here, if you have a problem in t-drive from function, like, system mapping is not working correctly. So in the generated VHDL, you will still keep your key of components and names that you use. Like, for example, this timer here will take those names. Things like that are here, the logic used, the logic defined there. If you define a signal function, the name will be kept because this function will return an area which, so it's not very difficult. Because, yeah, it still keeps name, and although there is something, it is the fact that if you use this kind of abstraction there, like throw my transaction when something happened, and please add a pipeline stateless, because those functions were already verified by somebody else. And you don't have to rewrite it each time by hand. You can kind of type what you think, and it already works directly because you are using a more abstract way to define the hardware. You have much less bugs coming in your description. And really, sometimes it's really unbelievable. Like, you know, when you are doing VHDL and Veridoc, it never works the first time. But by using those approach, really, sometimes it happens. Already, sometimes it is surprising. But, yeah. Then you can take a look in the generated VHDL if you are really not sure and there is something strange. So the generated VHDL is not crap. It is readable. If you search about your signal name, you will find it. It will still keep the same. If you use one statement, you will still retrieve them in the generated VHDL. So it is not a mess. It is right. But normally, you don't have to go in the VHDL. You will still have points where you can prop signals, and that will be right. Thank you. Question in the front. Hello. Nice. Fort Krak. Ever heard of system level design languages like System C or Spec C? Because they do a very similar approach to the problem of raising the level of ever heard of them. So, yeah, I have heard about System C and the other one. Spec C. Yeah, Spec C. I don't know about Spec C. I don't know about it. So about System C, I know that you can use many features, or like all features that you want when you are using System C for simulation things. But then for synthesisable things, I'm really not sure that you can use all crazy features of System C. But I'm not an expert. I don't want to say crap. But I think with System C, when you want to come back to synthesis things, you will have to use a synthesisable synth set, which is much more restrict, and maybe not so much powerful. But maybe I'm saying some crap. No, you don't. But it's similar to VHL. Some things you only can use while simulating the whole process. You're still using sensitivity list and these kind of things, right? But you don't have to use sensitivity list. You can also use FIFOS for the whole communication, or you can introduce some buses. Very common to your approach, which I really like. So raising the level of abstraction to make everything easier so you don't just have to synthesize it down. OK, thanks a lot. We're taking the next question from the very back. Can you compare it to Chisel, which is also scala-based and also a high-level synthesis tool? Yeah, OK. So basically, before starting Spain-Electail, I was using Chisel. But I moved away from Chisel because of some bad feelings that I had. So I don't want to hurt Chisel. But there is really many features that are not working well in it. Like, for example, you can't use kind of multi-clock domain support. But not really. It didn't work very well when I used it. And for example, you are still forced to use, for example, synchronous reset, which are active height, these kind of things. I mean, Chisel, the team behind Chisel, from my opinion, focus on their needs. They are not seeing a Chisel like tools to solve problems of everybody since they have what they want. They don't go further. They don't polish it enough from my point of view. And really, now with Spain-Electail, I'm really much more happy with it. Because I have a page of my documentation which is talking about difference between Chisel and Spain-Electail. And there is really a lot of little things. We tell issue with Chisel, but which would completely break Chisel if you really want to use it in a productive environment. And about the synthesis, you mean? You have a question about synthesis, right? No, I just mentioned that it was HSL tool. But speaking of the differences, wouldn't it make more sense to just fix Chisel to address those differences instead of working it? Oh, I tried to. Yeah, OK. Now, first time, I started Spain-Electail to understand how Chisel could work behind the scene and then come back to Chisel and fix it. But yeah, it really appeared very fast that it wasn't patchable at all. I submitted some fixes and my Git pool were remaining on whether or without any interaction with the team, no feedback. So it was a development process issue, maybe from the Chisel team. But I tried. Really, I tried. All right. Next question from the front, please. Yeah, I think we all know the concept of IP cause with the standard HDLs we have. And how did you think about a review process of the library that is building with Spinal? And how could that happen? So you say, you don't want to rewrite code every time. So we have to reuse it. And how can we review it that it's good code? This is, OK. Basically, this is probably the next announcement that I really have to do in Spain-Electail. It is really something critical and complicated because when you have done something in the library, which comes on the top of Spinal-Electail, normally you don't have to go back and remove features that you have added. So until now, what is documented on the online documentation could be interpreted like safe. Like using stream to do things is safe because I really put many attention in it. But yeah, there is some work to do on the additional library directly with Spinal-Electail. And it will be one future way of exploration. Until now, I've already focused on Spinal-Electail things, on the core of Spinal-Electail. And yeah, the library is next step to go further. OK, next question from the front, please. Is it possible with Spinal HDL to create clockless logic? Or actually asynchronous logic? Clockless logic? So you don't have a fixed clock? So there's a handshake everywhere between every logic? Ah, yeah, yeah. And yeah, all the logic, everything, there is absolutely no clock, no flip-flop. No flip-flop everywhere in your design. So no. No, sorry. Yeah, I also wanted to ask you about another tool. Can you talk about the relation between your system and Bluesback that's based on Haskell and has been fairly heavily taken up by MIT and work rather well on things like H.264 decoders? So personally, OK, I hear about Bluesback, but I don't really know about it. I can't really talk about it, sorry. All right, any other questions? Now is your chance to have any questions from the internet? Nope. All right, if anything comes to your mind, please find a speaker afterwards. And before you leave, please take the trash out with you. With that, let's give a final round of applause to Shaul. Thank you.