3 ms·
Learned LGP-30 assembly language for my high-school's programming class back in 1973, but we didn't actually have one, or even access to one. The teacher had le
by drfuchs 7y ago
Learned LGP-30 assembly language for my high-school's programming class back in 1973, but we didn't actually have one, or even access to one. The teacher had learned on a (real) LGP-30, and thought that we students ought to learn how CPUs really worked before graduating to a higher-level language (NEAT/3 for the NCR Century 100 that the school district did have). So, homeworks were handed in on paper, and the instructor would run them in his head.
One aspect of programming the LGP-30 is that, by convention, to call function FOO, the caller would store the return address at $FOO and then jump to $FOO+1, where the actual code for FOO started. Then, to return, FOO would do jump to the address in $FOO. So, no recursion was possible by default. (There was a single instruction that did "Store the already-incremented PC at a given location, and jump to just after that location", so it was all very efficient.)
- masswerk 7y agoThis is really interesting, because this is how later machines did it (at least with sum call instructions). I was actually surprised that the Programming Manual suggested to insert the address directly at the final jump to return. (Regarding recursion, you could emulate a stack by storing the top of stack in a particular address by convention, say 0000, and fix up the 'r' command on the fly to insert PC+2 at this location. Then, every subroutine would look up 0000 for the top of stack and fix up its final jump to return. However, this would seriously mess up the accumulator and you had to store any return values in another conventional address, etc...)
- drfuchs 7y agoHmmm; you’re closer to correct than I. Actual details are covered in http://ed-thelen.org/comp-hist/lgp-30-man.html#R3.16 http://ed-thelen.org/comp-hist/lgp-30-man.html#R3.16 where it explains that the “R” instruction would store away the address part of what was typically an unconditional branch. So, it was only by convention that this would be kept at $FOO, and that FOO would return by branching to $FOO. A super-smart compiler (they existed) would know the address of the last instruction of each routine, and be able to R into that location directly before calling (actually, just jumping) to $FOO. One other cute thing was that all memory was on a spinning drum, and you could really speed up your program’s execution by placing variables at addresses that were just about to be under the read head when the current operation was being performed. Otherwise, everything had to wait for up to a whole drum rotation. Kind of the original “pipeline stall”.