For those, whom i failed to bore into hibernaiton yet, the supplementary.
http://www.bitsavers.org/pdf/dec/pdp7/PDP-7_AsmMan.pdf"PDP-7 SYMBOLIC ASSEMBLER PROGRAMMING MANUAL" (c) 1965
TL;DR
Notable is how octal opcodes are first class citizens, only optionally subtstituted by symbolic mnemo-codes.
In later Intel 86 assembler you would have to have a special "DB" or "DW" or "DD" psaudo-command to stream in raw data.
In PDP-11 MACRO it would be ".WORD" or ".DWORD" if i remember right.
In PDP-7 you would just key digits in.
This clearly coming from times when primary mean to write a program was exactyly a self-made memory dump (like Inel .HEX files, but octal)
The Assembler has, in its permanent symbol table, definitions of the symbols for all the PDP-7
operation codes, operate commands, and many lOT commands
Keywords? What keywords??? Just #define-like constants/macros!
...could only be made so in an "assembler" where octal literals were primary means to code instucitons, and symbolic ones were optional add-ons.
The user may also request the Assembler to assign variable storage for him by placing a # within
the first six characters of the variable. A symbol which includes this character is automatically
assigned a register at the end of the program, and a zero is placed in that register.
1. We see # symbol already havng a special place in the hearts oif DEC engineers aearly on. But the meaning of the symbol was very different yet. On PDP-11 it would mean "absolute non-relocatable constant, not using PC register current value as its origin"
2. We see the word "register" mentioned but isn't it use confusing? Oh, my...
The Assembler also handles literals for the user. The value of the expression contained in parentheses is called a constant and is automatically placed in an unused location by the Assembler. The address of that location is inserted into the instruction. In the example below, the address of the register containing 1 is substituted in place of (1).
Literal constant was assigned an address and placed forever into a register.
How's that to you, Pascal guys? Literal is no distinct from initialized variable :-D
This is a bit exoitic even from i8086 assembler perspective.
Variables
The user may request the Assembler to assign storage registers for him. These registers, whose
value may be changed while the program is running, are designated as variables. A symbol
(permanent symbols and pseudo-instructions must not be used) containing # or $ as one of its
first six characters, which is not explicitly defined elsewhere by use of a comma or equal
sign, is a variable. A symbol may contain a # any number of times without becoming multidefined, but this character is required only once, not necessarily on the first occurrence of the variable.
...any place...
...not necessarily on the first occurrence...
If i parse it right, i might user some VARNAME many times in the prohram, then just mention anywhere VARNA#ME once (yes, infix!) to have its "storage class" altered. But would i use VARNAME# or VARNAM#E instead, and - oh, the dreaded Off By One - it is silently ignored, with no errors emitted.
Times, they are a changing!
A storage register whose contents remain the same throughout the running of a program is designated as a constant. A constant can be represented by using a literal: an element or expression contained in parentheses. This type of element causes a register to be reserved in the constants table by the Assembler.
....a register to be reserved in the constants table...
My head goes PUFFF!!!
But so, the "Register"" term in 1960-s hardware meant just a memory location designated to have some specific data. Todayt we would call it a global variable.
Man, i feel lucky not trying to search for something like "list of registers of PDP-7 processor" - because neither processors nor registers (as we undertand the terms) existed yet!!!
Which, again, is common as a theoretic background knowledge, but running into it like into a wall leaves quite an aftertaste.
Currently unassigned variables are defined as the addresses of successive registers at the occurrence of the pseudo-instruction VARIABLES. The pseudo-instruction VARIABLES may be used repeatedly in a program.
If the pseudo-instruction VARIABLES is not used, the table of variables is automatically assigned
a storage block at the end of the program. Upon loading the program, the contents of all locations assigned by use of the variable facil ity are zeros.
Proto-DATA segment !!! But on that old hardware there was no distinction between RW and R/O data yet.
A variable containing $ causes a multiple number of registers to be reserved. The number of
registers to be reserved may be controlled by the pseudo-instruction BAR n. The element or
expression N specifies how many locations are to be allocated for $ variables. N is initially
set to three.
Proto-static-array !!!
Also feesls like predating BASIC's notion of declaring variable datata type by the postfix symbol.
If any symbols remain undefined at the termination of assembly, they are automatically defined
as the addresses of successive registers following the variables storage block and their definitions printed. That is, they are treated as variables containing #, but the user is informed of the assignment.
....when i was coming from school BASIC and "pen and paper ForTran" to Pascal - the rude demand to make varible declaations was infuriating. That daaamn stupid gatekeeper having nothing better to do than asking me to show my Variable IDs again and again? Go get some real job to feel your time!!!
LAC TST - loads the AC with the contents of register 477
LAC (TST - loads the AC with the value 477
NOT a typo, there is no "close parenthesis" concept yet! Parenthesis is a prefix, nothing more. Making a "recursive parser" to recognize paretheses was wastefully complex for then hardware.
...Except for snippets like
(1) creatign a constant register. HEre we suddenly need both open and closing parentheses and parser does care. C is for consistency.
EXIT = JMP I 20Remember me being lost about a stack and nested calls above? :-)
Oh, the "i" there...
Indirect Addressing
If bit 4 in the binary representation of a memory reference instruction is 1, instead of taking
the memory location referenced as the effective address of the operand, the contents of the
location referenced are taken as the effective address of the operand. Indirect addressing is
represented in the source language by the character I following the operation symbol thus:
LAC I 500
Not sure if i should cry "unconventional" or see it as precursor to MASM type qualifiers like
MOV AX, QWORD PTR [BX].
Assembler guys would hardly recognize "indirect addressing" as data type, but replace "indirect addressing" with "pointer type" and it is.
Still, PDP-11 MACRO made a clean break, and used really different mnemonics for addressing modes.
No error message is printed if a defined symbol is redefined in a parameter assignment
unless it is a permanent symbol
Proto-variables. Or should i call it preprocessor macro-variables?
...now, let's look at the slash symbol.
Talk about functional overloading (as in chess-like way too much burden, not as subroutine polymorphism).
COMMENTS
If the character slash / occurs, not immediotely preceded by an element or expression, all
characters between the slosh and the next carriage return are ignored. Illegal characters (see
page 7) are permitted within comments. Parity errors are ignored within comments also.
Examples:
/THIS IS A COMMENT
LAC A /AS IS THIS
400/ 0 /lAND THIS ALSO!
So what that
400 was and why? Scroll up to the very very beginning:
THE LOCATION COUNTER
In general, statements generate 18-bit binary words which are placed into consecutive memory
locations. The location counter is a register used by the PDP-7 Assembler to keep track of the
next memory location available. It is updated after processing each statement.
Note how "register" gets yet another meaning here. And internal "index" or "pointer" varable in the compiler itself. I beleive today it would be seen to avoid using a term in two different meanings within a manual.
The location counter may be explicitly set by an element or expression followed by a slash. The element or
expression preceding a slash sets the location counter to the value of that element or expression.
Subsequent instructions are assembled into subsequent locations.
Example:
100/ The next instruction is placed in location 100.
So, was it an element or an expression (and should it even make difference here? don't we today think of single constants ase a special, degeneartae case of expressions?)?
Sidenote: actually "element" there meant what we would name a token or an dientifier today. But not quite, not quite...
Any group of letters, digits, and parentheses which represent binary values less than 2^18 are elements. Values are assigned to elements by the Assembler or the Loader.
Talk about self-recursive declarations. I can not figure otu of this whether values go first or elements do.
Lurk more the slash though...
LOCATION ASSIGNMENT
The use of a slash V), if immediately preceded by an element or expression, sets the location
counter equal to the value of that element or expression.
Examples:
300/ LAC (56
BEG-240+A/ LAC (56 - The instruction is stored in location number BEG-240+A.
So, if you would think how ALGOL got the //-comments - this is probably the birthplace of that bad habbit.
BASIC's use of apostrophe-comments and intel assembler use of semicolon-comments look pristine and perfectly justified attempts at clean break here. But dirty ALGOL prevailed. In modern Pascal too.
Now, commas.
SYMBOLIC ADDRESS TAG
An element or expression which represents a location in memory may be assigned a value in a
number of ways. The user could utilize the parameter assignment feature thus:
A=. ADD 100
The symbol A is assigned the value equal to the location in which the instruction ADD 100 is
placed by the Assembler. If the symbol already has a definition, it would be redefined. The
user can reference this location later by the symbol A:
JMP A
Redefining goto labels!!! How's THAT to you, Niklaus Wirth? What you consider harmful now, Dijkstra???
Folks, isn't it all sheer delirium? I wish i had a time machine and a big stick (bigger than logrules), to have some softly spoken words with them who designed THIS...
The simplest way to assign a value to a tag is by use of the comma.
A, ADD 100
The value of A would be the same as in the first case; the only difference would occur if A
had previously been defined, which would result in the diagnostic MDT.
...and strangely we made a full circle and came back to the notion of once-assigned (bound, almosat-immutable) variables, as a syntax construct, saving programmer from accidental typos, but not seeking to prohibit all cases of intentionally unsafe overrides.
A single undefined symbol or an expression containing only one undefined
symbol preceding the comma has its value set equal to the current location.
Setting value to expressions? My head, my head, please don't leave me yet!..
It is explained later, though.
An expression preceding the comma which contains more than one undefined symbol causes the
error print TUA. If the expression to the left of the comma contains no undefined symbols but
is equal in value to the current location, it is ignored; otherwise the error print MDT occurs.
This feature is useful for verifying table lengths.
Examples:
A,
B+1, - Where A and B are previously undefined symbols.
101, - Where the number is the same as the current value of the location counter.
GEORGE+HARRY-4, - Where either GEORGE or HARRY are previously undefined symbols.
A nifty trick... But Mel would do without it.
I still left puzzled, if the "LEFT" label in the listing above - and it was a listing for "master tape duplicator" - a CRUCIALLY important utility which errors could brick the super-expensive machine - was buggy and never could be actually "compiled". Well, today all the books are printed from digital data, so probably some typography boy dropped the comma glyph when pre-mastering.
============
http://www.bitsavers.org/pdf/dec/pdp7/PDP-7_Brochure.pdfThe brochure. What should it have?
Well, obviously, glossy photos with perhydrole maidens, and lots of shallow buzz-talk, aiming to drive you out of your wallet before you started thinking what it specifically was what yujsut bought.
Glossy photos there are, but instead of maidens there is some man with black beard instead. And they say those were years of sexism and ageism, LOL.
The shock is though having found the processors commands explained there, between those advertizing photos! Not in the asm manual, not in instrucitons list, but in the commercial !!!
Page 8 (and a bit on page 7).
1. "Memory referencing instructions" - oh, the classification!
Rememeber what written about "Irish stew" (the Jerome's report edition) and also an eastern's
prior artIt, perhaps, made practical sense in the days when core memory was the most limited and slow sectin of the machine, but still, what a stew!
2. Good luck figuring out was "xct Y" is supposed to do
3. rather peculiar
isz Y instruction. If i got it right then it was, in Pascal terms,
for i := -10 do with eveyr loop ending as the variable reached zero. Sounds simple, right? Exotic, yet simple.
4. The primary operation,
add, used now extinct 1-complement negatives. And only the aux, supplementary
tad used now pervasive 2-complements.
Which details makes the aforementioned isz ascend to a "fridge horror" estate - so WHAT encoding was supposed to be used there?5. No conditional jump instructions, but plethora of "skip-if-X" opcodes, today we would've called them conditional prefixes.
So, if you ever wondered where the established Brittish gentleman ARM contracted his dirty habits of conditional execution - you know now. Yankees did it.Granted, from human perspective this is pretty intuitive and logical, branching and conditioning seems to belong to different boxes of building blocks. The history decided otherwise, though.
6. Exotic "deposit" instead of store/save/write. Yet common "Jump" instead of PDP-11 later "branch". Go figure
7.
cal Y - call the subtourint, Y is ignored - "feel joy, Feel Joy, FEEL JOY!!!!" (from a Slient Hill concerto. Or should i rather quote "Rejoice!!!" from Girl Genius?)
Well, i hope this abomination does not exist "in silicium" and is imagnary ghost created by assembler translator. In the years when every bit costed more than it's weight ion gold making a special instruction to have yet ignore the operand!!! OTOH, both Intel 8086 and MACRO-11 assemblers are now to have special distinct mnemonics for specific cases of more general opcodes, so probably thius was not a real command.
8. Now, you may call me an idiot. Mark would certainly have his chance. But i DID spent quite a few minutes trying to find return opcode. What the hell they named it and in which group they sticked it too.Yes, i did.
Caveat: there is NO return instruction. At all.
9. So, how are you supposed to return from a procedure?
You are not. Okay, you are.
You can read JMS instruction descripion. Then again. Then again. Then again.
Until THAT sinks in.
I would not even start to describe HOW wrong and twisted was what it did.
10. Then you go back to page 6 and read that "The PDP-7 Programming System inludes advanced FORTRAN Compiler". And something starts wrigglign in the darkest corners of your memory. You start to kinda sorta (but not for certain) remembewr that early computers were built to and sold for running Fortran, like the recent computers were sold to run Windowsand newer computers are sold to run Android. You kinda-sorta-maybe remember that the Fortran firstly did not allow for nested functions calls. Or was it recursive? Or reentrant? Googles is of little help, sendign you to som manual and tutorials mentioning no this crucial limitation. Deecades later Fortran 77 "invents" them but demands you to opt-in recursive funcitons with special "compiler directive", giving away that "decent funcitons do not play with themselves". Wikipedia (this time it was the last thing to refer to, call me an idiot again) is blunt that Fortran the program was invented before hardware vendors invented the stack, and recursive calls were not possible and were not part of the language indeed.
Make it sink.
UNIX was coded on a computer that prohibited functions to be called more than once, and that stored the return address in the function body itself.
B/C languages were mostly designed by persons who matured on computers lacking stack and lacking functions reentrancy.
Obscene...
11. There seems to be no INC/DEC opcodes in PDP-7, nor SUBTRACT
12. There seems to be COMPLEMENT opcode, which more traditionally should be code NEGATE, but - it does not specify if it is 1complement or 2-complement. I suspect it was 1-complement.
If true, this would make implementing out traditional 2-complement subtraction into a real disaster!!!
x := x - y
SUB X, Y ; x86
SUB @#Y, @#X ; PDP-11
LAC Y
COM Y
TAD (1)
TAD X
DAC X
eeek....
For people who grew with such instruction sets, the CISC should look an earthly paradise and RISC a conspiracy against mankind