README

CARDIAC

This is the home of Strange Query CARDIAC, the world's first full CARDIAC IDE, featuring:

  • Full support for the 1968 language as defined in the manual and implemented in my earlier compiler (and many others)
  • An interactive editor that understands CARDIAC opcodes and auto-completes the six-column listing style used by the manual and most listings on the internet today
  • A visual debugger that shows you the state of the machine at all times
  • A stupid fast emulator that executes CARDIAC at near-native speed. This emulator also compiles to web assembly, allowing you to develop and debug programs right from your browser.

But wait, there's more

This debugger is the only one in the world to offer integration with a real ANSI terminal emulator (via xterm). Now, for the first time ever, your CARDIAC programs can output text and colors and interact with users. Hello, World actually outputs the text "Hello, World!". The terminal supports both an easy mode and a more faithful mode if you want to try your hand at ANSI special effects.

Support for multi-tape overlays

CARDIAC memory is so constrained that it's hard to write programs that are interesting at all. This runtime helps you get around this with overlay support. Supply the runtime with a set of numbered tapes, and when you issue an HRS instruction with a nonzero address in the operand, the machine will look to see if it has a tape with that ID. If it does, it will load that program over the current program and start executing it. This is supported both in the runtime and in the debugger. To see it work, pick sortem from the debugger's examples: tape 1 reads 35 numbers and sorts them, then HRS 02 brings in tape 2, which prints them with their mean, minimum, maximum and median. Its source is in cardiac-code/sortem.

New and exciting sample programs

There are sample programs in the StrangeQuery/cardiac-code repo. Not a lot there now but you'll find every program from the classic 1968 manual as well as new ones I developed (with Claude's help, of course). This includes what I believe is the world's first CARDIAC quine.

The CARDIAC debugger: the listing, the 100 memory cells and the accumulator.

You can run it right now. For free. Just click here.

A quick CARDIAC rundown

The CARDIAC famously has a tiny amount of memory, only 100 addresses that each hold a single signed 3 digit value ranging from -999 to 999. Note that these are not binary values. The CARDIAC is not a binary computer. All operations are done against natural base 10 numbers and digits. Instructions and data share the cells. There's exactly one register that holds four digits so that it can support overflow. A program counter says which cell the next instruction comes from. There is exactly one branch instruction, addition and subtraction, and that's about it. I/O is a deck of cards, one number to a card, and output is cards punched with numbers. As mentioned above, this implementation allows input and output to go back and forth to an ANSI terminal.

Despite these humble resources, the CARDIAC is capable of a surprising amount of computation, something which I will demonstrate thoroughly over the next month or so.

Instructions

Brian L. Stuart addresses these in more depth on his CARDIAC site. I will have more to say about this later, but for now here is a quick rundown. The debugger offers an animated mode that will illustrate the effects of these instructions on the machine as they operate when stepping over your program in debug mode.

Every CARDIAC instruction is a three-digit word. The first digit of an instruction is the operation, the other two name an address, so 152 is CLA 52 (opcode 1; the second two digits name the address).

OpNameDoes
0INPread a card into the cell. If you're hooked up in ANSI terminal mode, this will read from the terminal.
1CLAclear the accumulator and copy the value from the named address into it.
2ADDadd the value from the named address to the accumulator
3TACif the accumulator is negative, jump to the address. Notice that this is the only branch instruction. This has a huge effect on what coding patterns run efficiently on the CARDIAC.
4SFTshift the accumulator: left by the second digit, then right by the third
5OUTwrite the value stored at the named address to the output tape. In the debugger, this value will show up in the debug console. If you launch the terminal, what you'll see depends on the terminal mode. If you're running it in easy mode, a value 65 will render on the terminal as the digits "65". If you're not running in easy mode, it's on you to translate text that you want to display to the ASCII character set. If you want to display the value "4" on the terminal you need to output 52. If you want to emit the letter "A" you need to emit 65.
6STOcopy the current value from the accumulator to the named cell
7SUBsubtract the value in the named cell from the accumulator.
8JMPjump to the address. CARDIAC is a little weird in the way it handles jumps. It doesn't really support subroutines per se, but every time you do a jump, a second jump instruction is written to the special location 99. This way, when a subroutine finishes, it can just jump to location 99, which will trampoline back to the instruction after the jump that called it.
9HRShalt and reset the program counter to indicate the named address. In this implementation, HRS looks to see if there's another tape with the ID of the named address, and if it finds one, it will load it and continue running it. If it doesn't find one, it will stop execution the same way all previous CARDIAC implementations have done.

You really have to hand it to the designer of this instruction set: there is a sly symmetry to these opcodes. Many of them come in pairs. Read and write, add and subtract, etc. Pairs of instructions like this are typically exactly 5 opcodes apart. So for example ADD has the value 2 and SUB has the value 7. INP is 0, OUT is 5. Load to the accumulator (CLA) is 1, store from the accumulator (STO) is 6. Branch (TAC) is 3, JMP is 8.

Art from adversity

The tiny amount of memory available, and the fact that code and data have to fight for that memory makes programming for the CARDIAC a fun challenge. Things that are typically nearly free on other platforms can be expensive on the CARDIAC, particularly branching. Other kinds of things are relatively cheap because this is not a base 2 computer. And some things are completely missing. No ANDs, ORs or XORs here. Self-modifying code is common, and other tricks like using a value stored in a cell as both an instruction and a constant value help save precious cells.

An example

Countdown prints 5, 4, 3, 2, 1, 0. Each line is a cell: address, contents, label, instruction, comment.

10  530  loop  OUT  n      print n
11  130        CLA  n
12  731        SUB  one    n - 1
13  316        TAC  done   below zero: stop
14  630        STO  n
15  810        JMP  loop
16  900  done  HRS  00
30  005  n     DATA 5
31  001  one   DATA 1

This program is bundled in the debugger. Press Step (F11) to go one instruction at a time.

Go ahead, give it a try! Click this link and Hello, World will be loaded and waiting in a familiar browser experience. Start stepping over the code and watch the debug console and terminal to see it go.

With grateful acknowledgement to Brian L. Stuart, who has had the coolest CARDIAC page on the web for many years.

Strange Query Lab