Go to content Go to menu

Doing computation

Apr 6, 10:15 PM

After getting Computer.Build’s output to successfully compile in Quartus, I’ve had to go back and wire up a few things I forgot. First, the program counter was never incremented, which optimized out a bunch of stuff. Second, the ALU operation wasn’t connected, so it got mostly optimized out. Both are now wired in, and I’m pleased to announce the first real computation done by a completely synthesized CPU! It’s taking the values 0×10 and 0×01 from RAM and adding them together into the A register, producing 0×11.

Quartus simulator waveform output

It’s a very small program, but it demonstrates that the processor is up and running. It doesn’t support branching, conditional branching, or indirect addressing yet, but those are fairly easy to add, since I can just write the RTL microcode and let Computer.Build do the rest! I do need to come up with a way of specifying conditionals in the microcode, but indirect addressing will require zero modifications to Computer.Build itself.

It compiles!

Mar 22, 10:19 PM

As of tonight, Computer.Build’s Clojure implementation successfully generated a complete microprocessor design. I had something close for about a week now, but I’d forgotten to hook up the control unit’s opcode signal to anything meaningful, so Quartus was optimizing away all of the instructions. Once that was fixed, everything compiled properly, and the states seem to be sequencing reasonably. I haven’t built any meaningful pieces of code for this processor yet, but I’m close.

This represents a major milestone for Computer.Build. I had originally planned on having both the Clojure and Ruby implementations complete last week (the half-way point for the semester), but other priorities and work on the paper I’m writing around this project got in the way. I’m still very much on track to have things wrapped up by the end of the semester, since all that really remains is re-implementing things in Ruby, testing, writing the paper, and maybe adding some cool features like a data path generator.

Now that the Clojure is making something meaningful, I can turn my attention to the Ruby version. I haven’t actually touched the Ruby since early February, but a lot of the work on the Clojure has been getting its state machine generator up to par with Ruby. The actual Computer.Build code that generates the state machine from microcoded instructions is not too complex, so porting it to Ruby will be fairly simple.

The syntax of the microcode, though, is bugging me. I really like the way the Clojure syntax turned out, but Ruby is getting in my way for its counterpart. I might end up overloading the <= operator in the Symbol class, but that just feels wrong. What I have right now feels awkward and verbose, but maybe that’s just the object-orientedness bugging me again.

The major side-effect of this project has been turning me into a serious Lisper. Once the code-is-data, data-is-code revelation sinks in, you sort of can’t go back. Any code I write now is going to end up looking a little bit Lispy, and attempts at macros in other languages will litter my code. I’m already taking a liking to Python generators for exactly that reason: they remind me of real macros. The data/code duality has been especially strong with Computer.Build because the Clojure implementation uses native data structures that look fairly code-like to define the microcode and state machine. It’s going to be an interesting experience switching back to Ruby and the world of objects now.

I came across MyHDL recently, and I must say I’m quite impressed. It’s very much along the lines of Computer.Build, providing a way of defining hardware in Python, and generating Verilog code from that. It uses Python’s ast module to manipulate and analyze your source code, letting you write pure Python and get back Verilog. You do need a handful of special decorators to tell the compiler what’s going on, but it can mostly figure things out.

The downside of the true AST approach is that it takes a lot of code. Thousands upon thousands of lines of code to recursively descend the AST and deal with the Python language. At least he didn’t have to write a parser, but there’s still a lot of work required when compared with an internal DSL like Computer.Build. For the Ruby side, I’m taking advantage of Ruby’s blocks and metaprogramming tricks to build an internal DSL with minimal effort, and Clojure lets me jump straight to my own language thanks to its Lisp syntax.

Besides being easier to implement, Computer.Build is focusing on a different domain. It’s not intended to support general-purpose FPGA development. Instead, it’s going to be a toolkit for building computer-like devices, with an instruction set and clock and all that jazz. As such, it doesn’t need to support nearly as much of any language as MyHDL does. I’m still working out exactly how much Computer.Build needs to do to support the design of microprocessors, but honestly I think it’s pretty close now that I have state machines working.

If I were starting from scratch on this project and focusing strictly on the FPGA target, I probably would have built this from MyHDL now that I know about it. Since this project is as much about Ruby vs. Clojure as it is about hardware development, I stand by my choices. MyHDL is a very cool tool, though.

A friend of mine pointed me toward a wonderful Master’s Thesis about using Bluespec SystemVerilog (BSV) to develop an H.264 hardware video decoder. The introduction provides a clear overview of why C-based reference designs fall over for things like H.264 encoding/decoding, and the body of the paper demonstrates how to apply BSV to serious problems.

My professor in Computer Hardware Design this semester, when asked about BSV, dismissed it with something along the lines of “kids invent new HDLs all the time, but real men use VHDL or Verilog.” I’m getting the impression this is a prevalent believe in the electrical engineering world. Instead of moving forward and developing better and better tools, electrical engineers get stuck with old technology that is rarely optimal for the job. Things like BSV come along with the potential to completely change the market, but nobody notices because they’re too busy solving the same problems over and over again in lower-level languages.

Bluespec SystemVerilog provides some of the kind of abstraction I’m going for with Computer.Build. It’s a great tool, and I’m totally using it for Advanced Computer Hardware Design next semester. Unfortunately, it fall short of supporting metaprogramming. Why in the world would you want metaprogramming with hardware? For the same reasons you do it in software! Syntactic abstraction makes problem and solution definitions more concise and closer to the actual problem domain. This paper talks about exactly why this is crucial for H.264 decoding, but it applies everywhere. The C implementations just pass around huge shared memory structures, but this isn’t how the actual process of H.264 decoding works. BSV provides some great abstractions that get much closer to the problem, and for this application may be the best tool for the job.

I’m going for even more with Computer.Build, though. My goal is to allow the development of a multitude of DSLs for defining different kinds of hardware. For one-off solutions, you’re probably better off with BSV, but Computer.Build is intended to solve entire classes of problems in a manner only doable with DSLs or some other kind of language-level abstraction.