News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: 8 vs 16 bit addition in z80  (Read 6464 times)

Gideon Zhi

  • Discord Staff
  • Hero Member
  • *****
  • Posts: 3532
    • View Profile
    • Aeon Genesis
8 vs 16 bit addition in z80
« on: December 02, 2013, 10:30:01 pm »
So I'm hacking on Royal Stone's new/load/etc menu, and I'm getting screwed by an 8-bit adder.

Code: [Select]
6926  3E LD A, 40h                                 AF:0000 BC:0202 DE:3BD0 HL:C7E3 IX:CAE5 IY:C7B2 SP:C744 Cy:35517106   
6928  83 ADD A, E                                  AF:4000 BC:0202 DE:3BD0 HL:C7E3 IX:CAE5 IY:C7B2 SP:C744 Cy:35517113   
6929  5F LD E, A                                   AF:1001 BC:0202 DE:3BD0 HL:C7E3 IX:CAE5 IY:C7B2 SP:C744 Cy:35517117   
692A  E7 RST $20                                   AF:1001 BC:0202 DE:3B10 HL:C7E3 IX:CAE5 IY:C7B2 SP:C744 Cy:35517121   

DE contains a VRAM address, and 3BD0+40 is obviously not 3B10. Is there an elegant way to fix this? And a reasonably good assembler, while I'm at it? I've never done any actual z80 outside of a hex editor before.

dshadoff

  • Full Member
  • ***
  • Posts: 158
    • View Profile
    • Homepage (really old)
Re: 8 vs 16 bit addition in z80
« Reply #1 on: December 02, 2013, 10:34:03 pm »
Not enough information included here...

What do you think is supposed to happen here ?

Are you expecting to get 3C10h ?
You'd need to INC D depending on the state of the carry flag...


More to the point... you say you're hacking, but what was the original state (are you showing original code?), what is the state you want it to be in (are you trying to add a larger value than the code originally dealt with ?), and what are your constraints - ie. cycles, bytes, etc.
« Last Edit: December 02, 2013, 11:00:03 pm by dshadoff »

Malias

  • Sr. Member
  • ****
  • Posts: 303
    • View Profile
Re: 8 vs 16 bit addition in z80
« Reply #2 on: December 03, 2013, 12:35:25 am »
What about something like this?

Code: [Select]
6926  3E LD A, 40h
6928  83 ADD A, E
6829  30 02 JR NC, 682C
682B  14 INC D
692C  5F LD E, A
692D  E7 RST $20
« Last Edit: December 03, 2013, 12:56:40 am by Malias »
The great achievement is to lose one's reason for no reason, and to let my lady know that if I can do this without cause, what should I do if there were cause?
     ~Don Quixote~

Gideon Zhi

  • Discord Staff
  • Hero Member
  • *****
  • Posts: 3532
    • View Profile
    • Aeon Genesis
Re: 8 vs 16 bit addition in z80
« Reply #3 on: December 03, 2013, 12:51:49 am »
This is the original code, yes, but I've altered the starting vram address of the routine. This prints out information on three save files, in a loop, starting at 3B90 and adding 80 to the start address each time (so entry #2 is printed at 3C10, then entry #3 is printed at 3C90.) Each 40 bytes represents a line of tiles in VRAM. The issue is that, in an effort to utilize the space originally reserved for dakuten diacriticals and expand out the names of the towns the player can save in, I've moved everything up a line so it starts at 3B50. Each entry still takes up 80 bytes, so entry 1 should start at 3B50, entry 2 at 3BD0, and entry 3 at 3C50. The text is still rendering as if the diacriticals were present (removing that breaks just about everything else in the game) - it's just starting at a different address. The origin address, as it were, is the address that the diacritical gets printed at, while the text gets printed at the next line down - diacritical + 40, as it were. The problem is that this particular print routine isn't expecting text to start at xxD0 in VRAM, so when it adds 40 to the address of the diacritical to get the address of the text itself, well, this happens.

Malias - I'm guessing that would probably work, but I'm going to need to put the code somewhere else (hence my question about assemblers.) Edit: to clarify, I'm not really familiar with the zilog z80 instruction set, and I was hoping for an in-place solution.
« Last Edit: December 03, 2013, 01:01:30 am by Gideon Zhi »

dshadoff

  • Full Member
  • ***
  • Posts: 158
    • View Profile
    • Homepage (really old)
Re: 8 vs 16 bit addition in z80
« Reply #4 on: December 03, 2013, 01:25:31 am »
I see.  The problem is that you're constrained on space.

I think Malias' solution is probably the closest to what you're really looking for (although it's bigger than the original code).

I think you're probably going to have to relocate this piece of code, *or* avoid lines which would force the math to cross a 256-byte boundary.

Malias

  • Sr. Member
  • ****
  • Posts: 303
    • View Profile
Re: 8 vs 16 bit addition in z80
« Reply #5 on: December 03, 2013, 02:08:48 am »
Sorry, I'm in the same boat; The only z80 assembly I've done is either in a hex editor or an emulator. This might be of interest:

http://clrhome.org/asm/

FWIW here's a more efficient version of my code: As CUE pointed out, this won't work so never mind.
Code: [Select]
6926  3E 40 LD A, 40h
6928  83 ADD A, E
6929  5F LD E, A
692A  B1 XOR A
692B  8A ADC A, D
692C  57 LD D, A
692D  E7 RST $20
« Last Edit: December 03, 2013, 03:45:25 pm by Malias »
The great achievement is to lose one's reason for no reason, and to let my lady know that if I can do this without cause, what should I do if there were cause?
     ~Don Quixote~

CUE

  • Jr. Member
  • **
  • Posts: 86
    • View Profile
    • Nasío pa'jakear
Re: 8 vs 16 bit addition in z80
« Reply #6 on: December 03, 2013, 10:27:26 am »
You can't put a 'XOR' before an 'ADC' because 'XOR' clear the C flag.

If HL is not used (5 bytes):
Code: [Select]
21 40 00 ld  hl,0040
19       add hl,de
EB       ex  de,hl

If HL is used you can use the first code, with the 'JR NC' (7 bytes)

If you want use only the 4 original bytes, you need add a 6-bytes routine:
Code: [Select]
7B -- --   ld   a,e
CD XX XX   call XXXX
...


XXXX:
C6 40 --   add  a,40
5F -- --   ld   e,a
D0 -- --   ret  nc
7A -- --   inc  d
C9 -- --   ret
« Last Edit: December 03, 2013, 10:58:01 am by CUE »

Gideon Zhi

  • Discord Staff
  • Hero Member
  • *****
  • Posts: 3532
    • View Profile
    • Aeon Genesis
Re: 8 vs 16 bit addition in z80
« Reply #7 on: December 03, 2013, 04:44:12 pm »
Thanks folks, I've got my code working. Since this was my first real foray into z80 and I didn't know what ops did what, even on a simple level, part of the reason I was posting this was to get a feel for the language. It's kind of weird, and very different from 6502! I'm still trying to get my head around the methodology.

One issue is that the original code used ADD rather than ADC, and I can't JR based on the parity flag, so I had to change the ADD to ADC. It seems a little wasteful to have an Add without carry operation that still sets an overflow bit, but whatever.

Here's the final code I ended up using:
Code: [Select]
  LD A, $40
  ADC A, E
  JR NC, $01
  INC D
  LD E, A
  JP $692A

I had to implement a similar fix elsewhere in the routine that rendered the menu, and a slightly different fix in the overall text engine, but it's all working the way I need it to now. So bully for me! Thanks :)

Malias

  • Sr. Member
  • ****
  • Posts: 303
    • View Profile
Re: 8 vs 16 bit addition in z80
« Reply #8 on: December 03, 2013, 05:32:44 pm »
I think you misunderstand what ADC does.  ADC will add the specified register to the accumulator along with the Carry Flag.  Plain ADD instructions can always set the carry flag.
The great achievement is to lose one's reason for no reason, and to let my lady know that if I can do this without cause, what should I do if there were cause?
     ~Don Quixote~

Pennywise

  • Hero Member
  • *****
  • Posts: 2357
  • I'm curious
    • View Profile
    • Yojimbo's Translations
Re: 8 vs 16 bit addition in z80
« Reply #9 on: December 03, 2013, 05:56:55 pm »
A good resource for Z80 instructions is that unofficial hardware doc for the GB. Granted it's not 100% true Z80, but close enough.

http://www.romhacking.net/documents/396/

dshadoff

  • Full Member
  • ***
  • Posts: 158
    • View Profile
    • Homepage (really old)
Re: 8 vs 16 bit addition in z80
« Reply #10 on: December 03, 2013, 06:31:00 pm »
I think you misunderstand what ADC does.  ADC will add the specified register to the accumulator along with the Carry Flag.  Plain ADD instructions can always set the carry flag.

Exactly.
ADC will now give you a pseudo-random value on the output, because the carry flag is not deterministically reset (based on the code snippet shown).

ADD would ignore the carry flag as input to the opcode, but would still set it as an output.

As a side-note, it's common in Z80 to do 16-bit math as an ADD on the lower-byte first, followed by ADC on the higher-range, whereas 6502 will have you do CLC, followed by ADC and ADC.

Zoinkity

  • Hero Member
  • *****
  • Posts: 565
    • View Profile
Re: 8 vs 16 bit addition in z80
« Reply #11 on: December 03, 2013, 06:55:39 pm »
World of Spectrum is a decent place to find some primers and ask Z80 questions.  The introduction to Z80 gives a quick explanation on exactly this problem.

I don't know if you're working with the GB, but it uses a truncated set of instructions.  They have a reference for the full instruction set there too.  It was pretty helpful when I had to hack a few snapshots to have the joystick preselected.

KingMike

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 7086
  • *sigh* A changed avatar. Big deal.
    • View Profile
Re: 8 vs 16 bit addition in z80
« Reply #12 on: December 03, 2013, 07:14:31 pm »
A good resource for Z80 instructions is that unofficial hardware doc for the GB. Granted it's not 100% true Z80, but close enough.

http://www.romhacking.net/documents/396/
In addition to adding and removing some instructions on the GB, Nintendo changed some of the opcodes of the instructions they left in.
"My watch says 30 chickens" Google, 2018

CUE

  • Jr. Member
  • **
  • Posts: 86
    • View Profile
    • Nasío pa'jakear
Re: 8 vs 16 bit addition in z80
« Reply #13 on: December 04, 2013, 03:30:44 am »
ADC = ADD + Carry_Flag, and you do not known the initial flag value, so the addition can be A=A+E+0 or A=A+E+1.
Replace your ADC by ADD to solve the problem.

Another version, without using reg A/carry flags/short jumps (7 bytes):
Code: [Select]
push hl
ld   hl,0040
add  hl,de
ex   de,hl
pop  hl

World of Spectrum is a decent place to find some primers and ask Z80 questions.  The introduction to Z80 gives a quick explanation on exactly this problem.
Yeah ;)