(all PDP-8 blog entries can be seen by clicking here)
Time to do something a little harder than adding two numbers together. For this program, I will write HELLO WORLD on the terminal. In most languages this is trivial. In assembler, it takes a bit more work.
First, I want to mention that I used the “Introduction to Programming” book to get this program running. It explains PDP-8 IO well
I really had fun putting this program together. PDP-8 assembler is pretty easy and you can quickly figure out how to use it. I haven’t written anything in assembler is literally decades, yet this was pretty easy to do.
Before getting into the program here are a couple of interesting items.
C’s ++ Operator and the PDP-8
Ever wonder how the language C came to use ++ to increment a variable? The old DEC computers had an option to auto increment registers which made memory access easier – you would access, say, location 200 via a register and it would autoincrement to 201 for the next access.
It has been my understanding that when C was written (and it was first written for a DEC computer), rather than try to figure out and optimize something like
to use the hardware’s autoincrement ability, they came up with the ++ operator which was a hint to the compiler what was going on and it could more easily make use of autoincrement when a programmer wrote:
The hello world program, below, uses an autoincrement register.
BTW, I should mention I DETEST the use of ++ and NEVER use it in my own C programs. I know, I am the only one.
What is the Point to Octal?
The other thing of interest, well at least to me, is the use of octal for the PDP-8. Very shortly after I started programming professionally on a 16 bit minicomputer, I found it very clumsy to use octal yet that was the normal method, at that time, for describing binary numbers.
So the characters “AB” would fit into 16 bits as 0100000101000010. We would write this in octal as %040502. But you could not look at that octal value and see the octal values for A (%101) and B(%102). I could usually see the right half of %040502 was a B but I would have to do math to figure out the left half.
Years later, hexadecimal became more widespread and that made sense. “AB” in hex is 0x4142. You can quickly look hex 41 up (if you don’t already have it memorized) and see it is an A.
I always wondered why we were forced to use octal in the early days of my career. Then one day it hit me like a bolt of lightening. The old systems’ memory sizes were based on multiples of 6 bits, not 8. the PDP-8 was a 12 bit architecture. The DEC-10 was 36 bits. Octal makes perfect sense in those systems (hence the old SIXBIT character encodings of the DEC-10).
So on the PDP-8, AB (in SIXBIT, not ASCII) is binary 000001 000002 or %0102 which is easy to look at and determine the actual characters.
Hello World Program
OK enough digression. Let’s get on to the program. Here it is:
/PDP-8 PAL ASSEMBLY LANGUAGE PROGRAM TO PRINT HELLO WORLD! *200 /LOCATE PROGRAM STARTING AT ADDR 200 AIX1=10 /SETUP AUTOINDEX REGISTER 1 CLA /CLEAR ACCUMULATOR CLL /CLEAR AC LINK TAD CHRSTR /LOAD 1ST WRD OF CHRSTR (WHICH IS /THE ADDR OF CHRSTR) DCA AIX1 /STORE THAT IN AUTOINDEX REG 1 LOOP, NOP /TOP OF LOOP TO READ AND PRINT STRING /I USE A NOP JUST TO MAKE IT EASIER TO /INSERT CODE BELOW THE LABEL. TAD I AIX1 /INCR ADDR IN AIX1, THEN LOAD AC FROM THAT SNA /IF AC IS NOT ZERO, SKIP NEXT INSTRUCTION JMP I [7600 /EXIT PROGRAM (BACK TO MONITOR) JMS TTYO /CALL OUTPUT ROUTINE JMP LOOP /REPEAT LOOP TTYO, 0 /TTY OUTPUT ROUTINE. THE FIRST WORD OF /A SUBROUTINE MUST BE EMPTY (0) BECAUSE /THE JMS INSTRUCTION INSERTS THE RETURN /ADDR IN THIS WORD. TLS /WRITE AC TO THE OUTPUT DEVICE (TTY) TSF /IF TTY IS READY, SKIP NEXT INSTRUCTION. JMP .-1 /TTY IS NOT READY, SO CHECK AGAIN CLA /CLEAR AC JMP I TTYO /RETURN TO CALLER CHRSTR, . /1ST WORD IS ADDR OF STRING 110 /H 105 /E 114 /L 114 /L 117 /O 040 / 127 /W 117 /O 122 /R 114 /L 104 /D 041 /! 000 /<EOT>
This is a pretty straight forward program and I commented every line to help explain what is hapening. The first section initializes everything. AIX1 is the first autoincrement register and will contain the address of the string to print.
The loop simply loads each character from memory into the accumulator and calls the TTYO subroutine to print it.
TAD I AIX1 increments the address in AIX1, then uses that address to load the next character to print from memory.
Calling a subroutine is a bit interesting as there is no return stack. Instead, the first word of the subroutine is left unused. When it is called, the JMS instruction writes the return address into that word. To return, you jump back to that address. NO RECURSION IS POSSIBLE!! Well, not unless you implement your own stack.
Note that to make life simpler, I encoded the HELLO WORLD! string in memory using ASCII NOT SIXBIT.
Normally, to encode a character string into memory you would use the instruction
TEXT /HELLO WORLD!/
which could create the string in memory in SIXBIT. For this simple program, it was easier to hand encode the table in ASCII.
As each character is read, it is tested to see if it is zero. If it is, then the program exits.
The TTYO procedure is interesting in as much as you cannot write a character until the terminal is ready. So this subroutine writes a character, then waits until it has been processed before returning control to the caller.
Here is the compile, load, and execution of the program:
Feb 2015 update:
Here is a video someone else created of entering and running this little program: