0

While learning Z80 assembly I've go a strange behavior that after declaring 2 numeric variables the value of the first one gets a totally different value.

Example:

    org 32768

    ld bc,(score1)
    call 6683
    ret

score1  defb 15
score2  defb 32

Printed value is 8207 - why and how to fix it? Without the last line everything is Ok. Printing the value with the other method gives the same result.

Alexey
  • 2,582
  • 3
  • 13
  • 31
  • 4
    You loaded 2 bytes not 1. So what you are printing is `0x200f` which has low byte 15, high byte 32 just as you defined. To fix, either define 16 bits or load bytes. – Jester Aug 25 '21 at 15:30
  • @Jester, combining 15 and 32 in binary gives 8207, ok, got it. By defining 16 bits you mean `score1 defw 15` ? `load bytes` you mean `ld bc,15` ? – Alexey Aug 25 '21 at 15:48

1 Answers1

3

Yes, exactly; using defw will increase the size of the data (2 bytes each) to match the data size specification of the instruction being used in code.

Code and data sizes have to match; each instruction that references data tells the CPU what size the data has, and, data declarations also have a size.  In many assembly languages, consistency is programmer responsibility — assemblers often do not complain about (size) mismatches.

The CPU never sees data declarations, it only sees instructions.  So, each and every time an instruction references data, it has to specify how (i.e. the data size).  The CPU doesn't remember or care about mismatches between code in one place and code in another place, or between code & data; it just takes one instruction at a time and does what that says.

Expanding the data to match what the code does is the easiest fix here because your print subroutine takes the argument to print in the bc 16-bit register pair.


Otherwise, you can change the instruction to use the same size load as the defb, namely byte-sized instead of word-sized.  This would be done using an instruction like LD c,(score1), which loads only the c 8-bit register — and this is appropriate for data declared to 8-bits using defb.

To continue and use the print function, however, since the print expects a value in 16-bit bc, the 8-bit value in c will have to be expanded to a 16-bit value in bc, by clearing b (set b to 0, or by sign extending into b).

If I got the endian wrong, then swap references to the 8-bit registers with one letters b and c in what I said above.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • Thanks for a detailed explanation. Just 1 question: you say `to match the data size specification of the instruction being used in code` - in my case it's `ld` which can copy both 1 and 2 bytes data. So more precise would be `data size must match the size of the register(s)`, correct? – Alexey Aug 25 '21 at 17:25
  • 1
    Sure, if you like. But the general rule I have given is correct and sufficient. The machine code instruction, *taken as a whole* (i.e. not just the opcode alone) specifies a data size. Whether this is done by suffixes (as in `ld.b` or `ldb` vs. `ld.w` or `ldw`) or is done by specifying registers (that can be either 8-bit or 16-bit) is important but the rule ignores the particular method of size specification, as the method differs on different processors' assembly language. – Erik Eidt Aug 25 '21 at 19:18
  • 1
    So, here with Z80 assembly, the instructions change the data operand size by using different registers instead of different opcodes. – Erik Eidt Aug 25 '21 at 19:20
  • 1
    Remember though, that the processor always takes the entire machine code instruction into account, no matter what the assembly syntax is. (Another assembler for Z80 could have chosen require ld.b vs. ld.w with registers of appropriate width but that would be redundant, so they don't usually do that.) If you want to look more into how that works with assembly vs. machine code, compare the machine code encoding of `ld c,(score1)` vs. `ld bc,(score1)` – Erik Eidt Aug 25 '21 at 19:22
  • 1
    And I might have spoken too soon -- if the `(score1)` addressing mode relates to the `(nn)` addressing mode, then the byte value can only be loaded into the `a` register, so that 8-bit value in `a` would have to be enlarged to 16-bits into the `bc` register (an extra instruction to copy byte from `a` to `c` would be required, another reason the first approach of using 16-bit data is better in this case). In short, the 8-bit ld instructions do not correspond 1:1 with the 16-bit ones; they have some overlap but also each has some unique capabilities. – Erik Eidt Aug 25 '21 at 19:33