PaulAche wrote:
Your explanation makes perfect sense! The only thing I'm struggling with is understanding how you got the linear address range from 0x9000. If I remember correctly, I can get the linear address by SS * 16 + SP. That would make the address range start at (0h * 16h) + 9000h = 0x90000 (20-bit value). How did you get the upper range value 0x9FFFF?
OK, first of all, SS * 16 + SP is right, but your calculation as written doesn't follow that, you do SP * 22 + SS (but you ended up with the same answer as if you'd written the correct calculation, which means you at least did the correct calculation, but if you're thinking one thing, writing another, and doing the first thing, you're bound to confuse yourself and others).
The first mistake is that you switched SS and SP around. The next is that you used the decimal digits for 16, but postfixed it with "h", which makes it hexadecimal 0x16, which is decimal 22. You should write either "16" or "0x10" or "10h". Also, try to stay consistent with what convention you use for notating hexadecimal, you're using "0xNNNN" in some places, and "NNNNh" in others.
Anyways, the lowest value SP can have is 0, the highest it can have is 0xffff (though you'll want to keep it 16-bit aligned in 16-bit code, and 32-bit aligned in 32-bit code, so the highest you'll generally see in practice is 0xfffe). So (0x9000 * 0x10) + 0x0 = 90000 and (0x9000 * 10) + 0xffff = 9ffff.
With SP at 0x0, if you push ax (for example) to the stack, the CPU will decrement the stack pointer by two, to 0xfffe, and then write the two bytes of ax to 0xfffe and 0xffff. When you execute pop ax, it will read the bytes at 0xfffe and 0xffff into ax, then increment the stack pointer back to 0x0.