I just started learning ez80 assembly, and I'm confused on how labels are read by the CPU.
Here I made an example program:

Code:

start:
    call one
    call two
    call three

one:
    ld a,$FF
    ld b,$FF

two:
    ld a,$FF
    ld b,$FF

three:
    ld a,$FF
    ld b,$FF

I compiled it with spasm-ng and opened in a hex editor and got this:
CD 0C 00 00 CD 10 00 00 CD 14 00 00 3E FF 06 FF 3E FF 06 FF 3E FF 06 FF
It starts with CD 0C 00 00, which is what I expected. The CD is for the

Code:
call one
line, and the 0C 00 00 points to 00000C, which is the code under the "one" label. What I'm confused on is how the CPU figures out what to execute here. Is it supposed to execute this:

Code:

inc c ;0C
nop  ;00
nop  ;00

or call the label:

Code:

ld a,$FF
ld b,$FF

Or something else entirely? I would expect that it calls the label, and executes the ld codes, but I have no clue how the CPU is supposed to differentiate label addresses from random opcodes.
What makes this more confusing is the fact that this code:

Code:

start:
    ld a,one

one:
    ld a,$FF

Compiles to: 3E 02 3E FF
I expected the 02 to be a 24 bit address, but it is just one byte here. Why is that?
Quote:
I would expect that it calls the label, and executes the ld codes, but I have no clue how the CPU is supposed to differentiate label addresses from random opcodes.


When the CPU gets the CD opcode, it knows that this is a call to a label. So the next three bytes will be read as an address. The CPU "knows" where execution is running in the code by what's known as the PC, or Program Counter. So the read address will get loaded into the PC and execution will continue from there.
Labels don't actually "exist" in the machine code that the assembler produces. A label start: is just an instruction to the assembler to create a symbol called start containing the address of the next instruction after the label, which is just a number.

The call instruction takes a 24-bit immediate value as an argument. That means the processor will always treat the three bytes after the CD byte as a number, rather than as the next instruction.

The CPU contains a register called PC (program counter) which holds the address of the current instruction to execute. When the call instruction gets run, it pushes the value of the PC (which has already been updated to the address right after the call instruction, so it would be $000004 in your example) onto the stack, then sets PC to the immediate value - in your example, $00000C. The processor then starts executing from that address.

If you later run a ret instruction to return from the subroutine, it pops that value off of the stack and puts it back in the PC register, which causes it to start executing from immediately after the call instruction again.

For your second example, you're seeing this behavior because the a register is only 8 bits, and as a result the ld a, N instruction takes an 8-bit immediate value rather than a 24-bit value. The size of the immediate value is a property of the particular instruction you're using, not the number that you're providing as an argument. If you were to use ld hl, one instead, you'd get 21 02 00 00, since ld hl, Mmn takes a 24-bit immediate value.
That makes sense, much less complicated than I was expecting. Does anyone know exactly what is going on with the ld code calling a label? It's not a 24 bit address anymore, so I'm confused on how it is supposed to work.
Starbyte wrote:
That makes sense, much less complicated than I was expecting. Does anyone know exactly what is going on with the ld code calling a label? It's not a 24 bit address anymore, so I'm confused on how it is supposed to work.


A label just defines a symbol containing a number (the address of the next instruction after the label).
You can then use that symbol anywhere where you could use a number - in your example one will expand to the number 2, so you'll get something equivalent to ld a,2. The assembler doesn't actually keep track of the size/bit-width of that number, or the fact that it refers to a memory address. Since the value fits in 8 bits in this case, it's valid to use it as an immediate value for an instruction that takes an 8-bit immediate like ld a, n.

Typically, when writing a program, the addresses of your labels would not be near zero (the CE locates programs at $D1A881), so they would take up a full 24 bits and you wouldn't be able to store them in an 8-bit register like a.
Another way to think of it is to assemble your code and take a look at the listing:


Note that addresses in ez80 are stored little endian so '0C 00 00' as part of the call instruction is actually
address '00:000C' as you can see in the listing.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement