For reference, Burroughs B5000 and Inmos Transputer were stack machines. DEC PDP11 had such flexible addressing modes that it could be used as a stack machine. I think Niklaus Wirth's Lilith may have been a stack machine (more than 20 years ago, my mind is slipping :-)
They really did not have any register name/number in instructions to find operands, because they were on the stack.
Instructions could load immediate (constant) values onto the stack, or load/store to memory.
So their was no add.w r0, r1, r5
or add.w eax, [#fe34]
. There was add.w
.
So an example (not at all accurate, it was more complex) of an assembler sequence might be
loadstack 0xfe34 -- got fe34 onto stack
loadstackindirect -- use address on the stack, to load the value at that address
add.w -- assumes we already have the other operand on the stack
-- result back onto the stack
To calculate and load a value in an array, the stack might be used because there might be no indexed addressing mode.
So instructions were small, and lots of work was done implicitly with the stack and stack pointer. IIRC Transputers actually had a stack of only three values, and the compiler (or developers) had to ensure that was maintained.
XMOS now sell a modern 'equivalent', and employ some of the same people.
It is over 20 years since I wrote Transputer code, so sorry for being a bit vague.
The UCSD Pascal system used a software defined virtual machine, which was a stack machine. The idea was to make something which was portable to new computers, but also easy to write, easy to compile to, and reasonable performance. It's virtual machine was defined in its own Pascal dialect. When it was ported to real computers, registers would be used to hold the stack pointer, and likely some ingenuity in how the top of stack was handled (by registers), in order to get reasonable performance.