What is the "right" way to write 8080 assembly?

86 views
Skip to first unread message

Patrick Jackson

unread,
Aug 9, 2023, 12:03:03 PM8/9/23
to Altair-Duino
When I write 8080 assembly, I use "variables" kind of like in C. So if I need X and Y, I'll go down to the bottom of the code and do a:

_x: db 0,0
_y: db 0,0

and then manipulate them like that.
For me, this is easy because I know exactly where those variables are in the program, and they couldn't possibly be accidentally overwritten without me really messing something up, instead of a missed return or something if I did them all on the stack.

However, I have never really seen this be done in the wild. The only time I've seen this is the mandelbrot easter egg in romwbw (not the actual one I'm referring to but close enough:)
https://gist.github.com/jblang/3b17598ccfa0f7e5cca79ad826a399a9

I see everyone else using the stack almost exclusively. I even see it in modern compilers and assembly too.
I'm not writing massive programs in assembly or anything, but should I move to using the stack instead of fixed memory locations for variables? When should I use one or the other?

Thomas Niccum

unread,
Aug 9, 2023, 1:07:52 PM8/9/23
to Altair-Duino
Hmmm, my recollection (not 8080 but other assembler/machine code stuff) is that you often use the stack because you want the program to be "re-entrant" meaning multiple users could be running the same code.  Each user runs the same code in memory, but has a copy of their registers including the stack pointer.  So if you use the stack for your variables, each user has their own  "copy" and the code is then re-entrant.  If you hard-code the variable positions, then it can't be re-used.

I'm sure I'm over-simplifying or remembering something, but I believe that is the gist.  
A few other benefits I can think of:
- By using the stack for local variables (ie local to a function), these variables become isolated from the rest of the program. When the function completes, those variables can be popped off the stack, ensuring they don't interfere with other parts of the program. So getting away from every variable being "global" is often a goal... helped by using the stack....
- By using the stack for variables, each function call can get its own copy of the variables, making recursion possible and more straightforward...
- Since the stack is dynamic and only uses memory as needed, you're potentially using memory more efficiently, especially if not all variables are used. Given the small amounts of memory many early systems dealt with, memory conservation was always a big issue.

On the downside you have to follow good stack hygiene and worry about overflows, persistence, etc.

Roger Linhart

unread,
Aug 9, 2023, 2:18:56 PM8/9/23
to Patrick Jackson, Altair-Duino
In your example, you are reserving two bytes (16 bits in total) for each label and setting the value of each byte to zero. You'll see examples in my code where I used "_x: dw 0" to accomplish the same thing and it is clear that I intend to use this for a 16 bit word, not the beginning of a two element byte array. ;) 

I'll share an example of mine using a similar technique. The github repo includes a link to my GERmulator project YouTube series.


--
You received this message because you are subscribed to the Google Groups "Altair-Duino" group.
To unsubscribe from this group and stop receiving emails from it, send an email to altair-duino...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/altair-duino/91a84a70-031c-47f7-84cc-d0b3a36b0a03n%40googlegroups.com.


--
Roger Linhart
Portland, OR  97230
Mobile: 541-690-8560

John Kennedy

unread,
Aug 10, 2023, 3:46:09 PM8/10/23
to Altair-Duino
You can most definitely, and I would say should, use reserved areas in memory like this for your "variables", as it makes code a LOT more readable and useable than trying to juggle everything on the stack.
You can obviously reserve a byte for smaller numbers or two for larger numbers, or even a block for strings. 

The stack is used for return address and using it for random data can make things more complicated and introduces risk IMHO that is not worth it.

Perhaps the first thing you need to decide upon when writing assembler is how to pass parameters between your subroutines (because writing everything in the form of subroutines is the only way to write something other than "hello World", and even then..)
Some people push values onto the stack and then call their routine, popping the values inside the routine and pushing return values back, or other variations of this. It's fine, but can lead to problems if you are nesting code or worried about interrupts taking you away somewhere else. I find that storing values in reserved memory as "variables" is preferable. If you would using a 6502 CPU, you would probably keep all your data in Zero Page (the first 256 bytes of RAM) for performance reasons. 

Assembly is low level enough that YOU decide upon the style, and as long as you're consistent, no-one can say you're wrong. And no-one else will understand it anyway ;-)

On Wednesday, August 9, 2023 at 9:03:03 AM UTC-7 gindiamon...@gmail.com wrote:

Patrick Jackson

unread,
Aug 10, 2023, 3:58:38 PM8/10/23
to Altair-Duino
Thanks guys! All very interesting. I've determined that yes, making subroutines is really the way to go with anything other than very small programs, and my new terminal is using a state machine with so many subroutines. It does make coding easier.

I'll take a look at using the stack for passing/returning where I think it would be applicable, it seems quite powerful!

Reply all
Reply to author
Forward
0 new messages