Reflections on SPIM

SPIM is a program that I wrote during my first year (1990) as a professor at the University of Wisconsin Madison, when I was starting as an assistant professor. It a software simulator for the MIPS processor, a RISC computer that was quite popular at the time, and which was subsequently crushed by Intel x86 computers. Originally I wrote Spim to help my students in a compiler class, who would otherwise have to generate code for the far more complex x86 processors (x86 won that battle, but subsequently added enough registers to make code generation simpler). Subsequently MIPS and Spim were used by David Patterson and John Hennessy in their undergraduate computer architecture textbook (and in several other authors' books), which isn't that surprising since John was the architect of the MIPS processor. Over the past 25 years or so, Spim has probably been used by a majority of computer science undergraduates in one class or another.

I am still actively maintaining Spim, which is a surprise to me. Maintaining means fixing a handful of minor bugs each year, answering questions, and putting out a new release between semesters (typically January). Given that thousands of students use Spim every semester, remarkably few things go wrong. But, I ask myself every occasionally: why don't I just leave it alone and let Spim become "abandonware". The current version works well enough that students would probably be able to run it for another decade or so, at which point most classes will have changed to ARM instead of something that the students' grandparents could have used.

I have several reasons why I continue maintaining Spim:

  • First and foremost, I have profited from Spim and feel an obligation to continue supporting people that use it for teaching. Between book royalties and a license to a company, I made the equivalent of several years of my assistant prof's salary at a time when I really needed the money. [Yes, a popular textbook was very profitable to the authors, including the author of an appendix who got a fraction of what the co-authors received.]
  • Second, I remain amazed that there are still bugs in SPIM. It is a fairly small, simple piece of code (120 files, 60k LoC) that has been used extensively. Why do bugs still emerge? It is humbling to a professor who researches and teaches software engineering to see how difficult it is to eliminate software defects.
  • It is also a good way to track the progress of software development. I wrote SPIM in C, because at the time C++ was a new language without a native compiler (only AT&T cfront, which translated it into C code). The code is clearly object-oriented C, but I have never translated it since works. The only tools I used were emacs, CVS (a version control system), and gdb. Today, the IDEs are far more sophisticated and SVN is a far better version control system. And, I still use emacs (also Sublime and vim, but I prefer the IDEs). But, the biggest improvement is the online code hosting sites (I use SourceForge), which make it far easier to share code and distribute new versions (check out the old webpage at UW).
  • Another measure of progress is the difficulty of providing a nice GUI interface on different platforms. The original SPIM was a terminal-only program without a GUI (still works fine after 25 years!). I added an X-window interface and subsequently a native Microsoft Windows interface. They looked similar, but were different enough to confuse students and professors. The architecture of SPIM is good (MVC, before the term was invented), but the interfaces shared no code. A few years ago, I said enough is enough and wrote an interface in Qt, an excellent cross-platform GUI toolkit. QtSpim now looks the same on MacOS, Windows, and Linux and I only support one code base. Hats off to Nokia and Qt's subsequent corporate supporters!
  • Releasing a new version is a continual reminder of how far we still have to go. Each release takes me roughly a full day to deal with Bit Rot. Software changes, not only the OS, but also Qt, compilers, tools, and packaging, and inevitably something breaks on all three platforms. This month, it was that the C compiler on MacOS started complaining about deprecated "register" declarations in the code produced by the out-of-date version of flex shipped by Apple (get your act together guys!). On Linux and MacOS, the Qt framework had changed and a number of libraries and plugins no longer exist, which broke the packaging tools. On Windows, the MacOS-required compiler flag to suppress warnings wasn't supported by the Microsoft C compiler and the commands to build the documentation stopped working ...
  • Doing releases has provide me with good insight into the shortcomings of Linux and the open source community. Sure, I have full source code, but I would prefer to have a single well-thought out packaging system like the Mac or Windows and excellent tools for building packages, rather than Linux's RPM and Debian formats. I only support the latter since I use Ubuntu and I don't want to do the extra work to provide Spim two redundant package formats and on the vast number of repositories on which Linux software is disseminated. The full source code is online, so someone else could do the work (or it could be automated), but the repository maintainers seem to believe that program maintainers have the obligation to build and upload to their site.
Anyways, it has been a fun hobby over the years, and source of endless amusement to my kids ("dad is working on SPIM again. why can't he get it right?").

Nerdy details: Out of the three package systems, I think that MacOS got it closest to correct. On the Mac, an application is a directory that holds the executable code, libraries, and resources. It makes it easy to see what is in the application and easy to remove it (though, apps leave a lot of cruft behind in the Library directory). This structure lets me ship Spim with all of the Qt libraries, in one file so that a user only installs QtSpim and never needs to know about Qt. Windows does not put the files for an application in one place, and without some extra work, is still susceptible to "DLL hell", but the packaging tools are good and it isn't too hard to do a side-by-side installation that eliminates that problem.

Linux has a different model (at least as I understand it). You are supposed to ship your executable without libraries, but with a list of dependencies. The installer is supposed to look around the system and download the missing libraries. This is a good idea in theory, but in practice, it is a pain in the ass and error prone. First, to ship Spim, I need to find a standard set of packages that contain all of Qt libraries that Spim use. I never found this package. The standard Qt package contained most of the libraries, but not all of them, and I never found any package aside from the full Qt download (hundreds of MBs) that contained the missing packages.

Also, the dependency mechanism makes me nervous, as it can download a later version of a library (e.g. require version > 15.2) that Spim was not tested with. I could require a fixed version, but that seems to be against the optimist convention that releases will not break functionality.

In the end, I just distributed Spim along with the Qt libraries on Linux, just as I did on MacOS and Windows, and you know what, no one has complained.

Bit rot rolls on... With the 9.1.19 release of QtSpim (summer 2017), the installer creation program that I was using on Windows disappeared. It was a free, limited version of InstallShield distributed with Visual Studio 2012, and apparently an update to VS deleted it (thanks Microsoft!). It took me a couple of days to move over to WiX, an open source installer creator. It is a quite nice tool, and would have been a better starting point, but I would have been much happier do productive work during those two days and continuing with InstallShield.

Comments