Show HN: Retrocomputing with Clash: Haskell for FPGA Hardware Design
unsafeperform.ioIt was an interesting choice to include the Compucolor II emulation. It was a very quirky machine with some interesting design choices, but not very popular.
Ops website references https://compucolor.org, which I created. I'm glad someone was able to find something useful in it. The site has an in-browser javascript emulation of the Compucolor II. I've written one javascript program in my life, and that emulator is it. It has languished since 2014 other than a bug fix here and there. Eventually I'll refresh the code, and hopefully replace the display generation logic with webgl.
The core emulator was quite simple to write, but 90% of the time was spent getting the code to work across browsers and dealing with the infuriating differences in keyboard handling. Maybe things are better now.
Your website is of course referenced in the Compucolor II chapter of the book. It was invaluable in getting my Compucolor II implementation working. In fact, I even sent you a PR to fix the TMS 5501 chip's behaviour to match its datasheet (https://github.com/jtbattle/ccemu/pull/2/).
I chose the Compucolor II for its simplicity. Its original design goal of cheapness via very small number of components translates is a big win for my purposes because implementing many small special-purpose chips would bloat the book considerably, without adding too much extra value. With the Compucolor II, we can just take the Intel 8080 core from an earlier chapter, implement two custom chips, take the UART from another earlier chapter, and boom done.
In fact, I chose the Intel 8080 in the first place instead of the more widely used Z80 for the same reason: adding the Z80 extensions wouldn't bring anything new to the table, but would increase cruft. Turns out there's a small but reasonable number of 8080-based home computers (https://retrocomputing.stackexchange.com/q/11682/115).
I am having trouble understanding the usefulness of all these new pseudo-HDL languages.
In all the projects that I've worked on, the choice of HDL (which was 95% of the time, Verilog, for the rest, VHDL), was never actually 'important'; the language features were never critical to the completion of the project. Verilog is fully adequate for any kind of serious HDL development.
What mattered were, the tooling, IDEs, debuggers, timing analysis tools, verification infrastructure, the IP ecosystem, etc.
Perhaps I am getting old but I just can not see how these new languages can be a serious alternative to Verilog/VHDL.
The same could be said about ASM. You can complete any project with it, the tooling is very good. It will just take much longer and you will have to debug more.
In that sense no language ever is important. The point of a language is to allow the developer to write code faster and in a more secure manner. In both of these clash is vastly superior to vhdl or verilog.
Imagine a world were we would still be stuck with C because people don't understand the point of improving on it. I think this would have had societal level consequences with what we would have been able to do with computers.
But, HOW do you debug Clash?
For example, what is the design and debug flow of using Clash to target a Xilinx FPGA?
My guess is that you're going to tell me I will have to debug the generated Verilog code?
Debugging via high-level simulation is something my book spends a lot of time on. If you look at the sample chapters, you can see that the same Clash code can also be compiled into software Haskell, which you can then interface with non-synthesizable test benches, such as an interactive SDL frontend. So you can take your HDL logic and run it directly, interactively in real time. You can play Pong by compiling the code as software.
One level lower, you can use Clash's signal-level simulator. Basically it gives you a synchronous stream of signal values, either as a lazy list (for "offline" simulation), or as an automaton that you can turn the crank on by feeding it the next clock cycle's inputs (for "online" simulation, i.e. where you want to do IO to compute the next input from the previous outputs). So at this level, you'd take your Pong circuit and use the automaton interface of the simulator to feed the virtual "pushbutton" states computed from e.g. keypresses, and then consume the output to do the rendering. Or simulate the whole circuit end-to-end and feed its output into a VGA interpreter, which you also get to write in Haskell.
If you need to debug at the Verilog level, you can use Clashilator (https://github.com/gergoerdi/clashilator) to automate FFI-ing into a Verilator-generated simulation.
I've been using Clash for about 2 years now. I just debug the clash code. As in just use the normal Haskell test tooling. The only reason I ever read the generated HDL is when I make sure I have integrated another IP correctly.
qq: i know that for HLS sometimes (most?) the generated HDL is 10x the number of resources (flip-flops?) compared to hand-written HDL. how bad is clash in this respect?
Clash is not HLS. You have full control of register placement and pipelining just like VHDL and Verilog. Clash in that sense is not "higher level" then VHDL or Verilog. In some respects you could even say that Clash is "lower level" because you don't write things just right to be inferred correctly. You actually specify what hardware you want. E.g. you write I want a blockram with this size here, and not if I write this specific Verilog the tools will infer a blockram.
What Clash gives you is the power and tooling of Haskell.
>Clash is not HLS
i don't understand - how do you generate the bitstream if you're not generating verilog or vhdl first?
Clash does generate Verilog or VHDL but the only reason it does this is to interface with vendor tooling.
HLS generally means you compile a very high level description of computation to VHDL/Verilog. This high level description doesn't contain hardware details like registers, ram usages, pipelining etc. During the process of HLS the synthesis tool will try to translate this description to a digital circuit. It will itself place registers, rams pipeline as necessary.
That is the reason HLS doesn't reach the performance of VHDL/Verilog, these HLS tools just aren't as good as a human making the digital circuit.
Clash is not itself coming up with a digital circuit like HLS is doing. The developer is specifying the digital circuit. Just like with VHDL or Verilog. It's just an alternative way of writing it.
got it - it's like chisel. thanks
Looking at your posting history I can be a little more concrete: Chisel is essentially a metaprogramming framework for VHDL/Verilog. Clash is a compiler closely based on GHC that compiles Haskell code, not a DSL defined within Haskell, to VHDL/Verilog.
you're saying seemingly contradictory things (that would best be resolved for me if i just dug into clash, so i will):
>HLS generally means you compile a very high level description of computation to VHDL/Verilog.
...
>Clash is not itself coming up with a digital circuit like HLS is doing. The developer is specifying the digital circuit.
...
>Clash is a compiler closely based on GHC that compiles Haskell code
what does it mean for clash to compile haskell code but not to come up with a digital circuit? haskell code (afaik) doesn't represent combinational or sequential logic. well maybe it does using clash (thanks to haskell crazy metaprogramming faciilities) but then what does it mean to "compile"? verilog isn't compiled, it's still synthesized to gates and luts and whatever right? what does clash compile to natively if not verilog/vhdl (which then gets synthesized)?
It's not contradictory. A Haskell function(modulo io and boundless recursion) gets compiled to combinational logic without registers. a digital circuit circuit in clash are normal Haskell function combined together with registers and other combinators. Clash can compile to an executable as well as to hardware. The executable is a cycle accurate simulation of the circuit.
Not exactly. Chisel is a DSL while clash is not. But it's at the same level of circuit design abstraction.
Clash is not pseudo, it's actual HDL. Right now it compiles to Verilog, yes, but this is minor a technicality.
> the choice of HDL (which was 95% of the time, Verilog, for the rest, VHDL), was never actually 'important'; the language features were never critical to the completion of the project
Because both are equally bad, and have little meaningful difference in their features.
> Verilog is fully adequate for any kind of serious HDL development.
This confirms my past experience of interacting with hardware people. They have extremely low standard for their programming languages and tooling in general, and don't like reflecting on these too much. They just suck it up and do the job, no matter what.
My Verilog just quietly accepts the code which assigns values to a wire which is declared as input? I guess it's my fault, I will just be more careful in the future not to do that again.
My Verilog doesn't allow parametrizing modules with anything other than natural numbers? Well, I'll just duplicate code, that's how we always did it.
My Verilog has no types other than "wire" and "array of wires" (and also allows assigning array[2][3] to array[3][2] emitting no warning)? It's fine, I will just try to keep in mind what data I have in which wires and try to make sure I never mix things up.
My Verilog uses pseudo-imperative code with "assignments" in it to describe a network of flipflops with combinational logic between them? It's ok, I will just train my brain to convert between the two even though there's no good reason for Verilog to be like that.
My Verilog has constructions which are synthesizable only when used in one very specific way, instead of clearly differentiating between synthesizable (actual hardware) and un-synthesizable (imperative testing code)? It's ok, I will just remember the details.
My Verilog produces so much noise in the build logs that nobody actually reads it unless something breaks? I guess I just have to be more careful or write more testbenches.
> I just can not see how these new languages can be a serious alternative to Verilog/VHDL
This is learned helplessness.
Clash has better, more natural abstractions for the wires and flipflops. Combinational and sequential logic are clearly separated. It also uses many primitives of Haskell which make your code more compact, easier to read and verify. You can parameterize modules with anything, including other modules, this drastically reduces code duplication and lets you manage the code on a higher level (while still seeing how does it correspond to bits and wires).
As the GP points out the problem you're up against is the tooling - to be mainstream a new language needs to be supported by the main commercial ASIC tool chains - synopsys/cadence/etc, the tools from each of the FPGA, as well at least one high performance compiled simulator (probably running on both linux and windows) - then you need coverage tools, linters or equivalents, plus you need to be able to access IP libraries in all the tapeout synthesis targets (which probably means mix and match with existing verilog and vhdl libraries and IP generators).
It's not impossible, but it is an incredibly big chicken and egg problem where most of the pieces are out of your control - the best you can do is to make highly efficient (ie synthesises well, simulates well) verilog or vhdl and hope enough people start using your tooling that the big vendors choose to implement your language as a target.
(oh and My (system)Verilog has far more types than just wire, is accepted by the big guy's tooling and generate allows me to avoid almost all copying)
I'm trying to look at one specific component here, the language itself. My claim is that as a language Clash is way better than SystemVerilog.
True, Verilog has more mature tooling and is better supported by vendors at the moment. But most of it is because Verilog is old, and because hardware people have little knowledge of (and demand for) good programming languages; not because it's a good language (maybe it's better than the other even worse languages, but it's not good by the software programming standards). It's not that Verilog is somehow inherently good for implementing tooling for it, absolutely not better than Clash.
> far more types than just wire
You mean integers and C-style structs? “Far more” is a big stretch here. And these “types” are not very useful: they are only used to decide how operators should behave on values. As far as I remember, even Verilog's assignment doesn't care about types, as long as left- and right-hand side have the same number of bits, the assignment is allowed.
> generate allows me to avoid almost all copying
At the cost of: extra work (you're essentially implementing polymorphism by hand), inferior readability, increased risk of making mistakes, no support from the compiler. Generate can be almost perfectly replaced by code generation in Python.
Seriously, look at the way Clash allows parametrizing things, you will be impressed.
It's not that we have a low standard, it's that we are bound by the full suite of tools that are provided to us in order to achieve our design objective.
When I am close to tapeout and I am moving a single gate across a flip flop in order to extract the final few Mhz out of the design, and my formal equivalence checker only understands Verilog, I will have to use Verilog.
I suppose my benchmark in assessing the capabilities of this -or any- language and its ecosystem is the following : Can you use Clash in the design of a reasonably complex chip from scratch (HDL to tapeout)?
Software people also have deadlines, less strict than hardware sometimes, but they still do. If people in Silicon Valley thought the same way as hardware folks, we would be using Java for all applications and Oracle databases. But instead we have a huge ecosystem of open source databases to choose from and and a plethora of languages designed for different tasks.
I worked at Intel designing tools for hardware people to use (I am also a hardware person, but I see the power of software) and it was years of hair pulling to get anywhere, even in the face of clear advantages being offered.
Why isn't there an open source simulator as powerful as vcs out there? Why don't we have open source timing analysis tools? Because the culture just doesn't encourage exploration in these areas. And if you try, people will just not take you seriously.
I don't know what is tapeout, but Clash can describe any circuit that Verilog can. If you wanted to, you could one-to-one translate the circuit descriptions between the two.
We could argue about the current state of tooling for Clash and its ability to work together with vendor-specific tools and other ecosystem stuff, I don't know much about this. But as a language Clash can do everything Verilog does.
>I don't know what is tapeout
The person you're responding to isn't an FPGA dev (or at least not primarily). They're talking about verilog for ASIC design where the last step is is making the lithography mask that "tapes off" parts of the silicon substrate (like a painter tapes parts of a wall when painting).
I play in the space (Chisel and FIRRTL and CIRCT) so I agree with you but you're being far too dismissive of the people you're aiming to convert.
>But as a language Clash can do everything Verilog does.
Ironic since people say the exact same thing of Haskell and eg python and yet we still don't have wide Haskell adoption.
You have to deeply internalize that a PL or HDL is a tool. Thus, this position makes zero sense
>its ability to work together with vendor-specific tools and other ecosystem stuff, I don't know much about this
No one uses tools that don't fit somehow into their workflow. Further, if the users of the tool are happy with their current toolset then you have a very hard road to hoe in convincing them to adopt your tool.
Sorry it it came out as dismissive. I only wanted to show that my claim is specifically about the language, not current state of tooling which I'm not as familiar with (and which is important).
I'm looking at it through another lens - a way to improve my intermediate haskell and learn about HDL. Maybe they're pushing for commercial use but there are alternative reasons to be interested in this too!
The purpose of making anything Haskell-based probably is making it mathematically verifiable. Isn't it?
Previous discussion on HN about Clash itself:
https://news.ycombinator.com/item?id=23096338 https://news.ycombinator.com/item?id=9516217
I had so much fun a decade ago in University creating a game that ran on an FPGA. We were generating the RGB signals in the FPGA so we only had a little time between screen refreshes for an game logic. It was very challenging but very fun. We made a little scorched earth clone. That game worked amazingly well given the constraints of the system.
For anyone wanting to learn these systems I'd highly recommend developing a game as a learning project.
In the book (see the sample chapter 8 at https://unsafeperform.io/retroclash/#samples) we create a proto-almost-game (just a bouncing ball) first by directly wiring together signals.
However, the resulting circuit description is much harder to understand and extend than a more structured approach, so we rewrite it in a more principled manner by decomposing it into two parts: a `Input -> State -> State` circuit used as a register transfer enabled by the start of the vblank, and a `State -> Coordinate -> RGB` circuit connected to the video output signal generator. This has the added benefit that we can compile the same description as software Haskell instead of hardware Clash, and so we can use high-level simulation to run the bouncing ball in an SDL window.
Sample chapter 9 then creates a Pong game by just changing these two (pure, Haskell) functions slightly. With minimal changes, we go from idle animation to playable game!
Awesome! You have a customer :)
By the way, I recently had an idea while taking shower: can there be such a CPU (e.g. FPGA-based) that would support algebraic typing on the hardware level?