[Z80] PV flag on 'aluop' (add/adc/sub/sbc/and/xor/or/cp)

Got questions? Got answers? Go here for both.

Moderator: MaxCoderz Staff

Post Reply
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

[Z80] PV flag on 'aluop' (add/adc/sub/sbc/and/xor/or/cp)

Post by benryves »

This flag is giving me some grief.

Firstly, I'm assuming that;
  • For add/adc/sub/sbc/cp it represents overflow.
  • For and/xor/or it represents parity.
I need to ask as ZiLOG's official user manual states:
  • AND: P/V is reset if overflow; reset otherwise (huh?)
  • OR: P/V is set if overflow; reset otherwise
  • XOR: P/V is set if parity even; reset otherwise
This is all a bit baffling. Given that ZiLOG don't know their left from their right, I'm going by the definition everyone else uses, and that they're all parity.

That moves me on to the real issue; overflow.

I'm currently taking the first operand as an unsigned byte and casting to an int (signed). I then take the second operand (also unsigned byte) and also cast to a signed int. If it's an adc or sbc instruction and the carry flag is set, I increment the second operand. I then either add or subtract the two.

If result < -128 or result > 127, I set the overflow flag.

This is clearly not right. What is the correct behaviour? I'm assuming it's to do with the treatment of signed/unsigned values, and changing these around results in different CRCs (eg using a signed byte first) but they're all still incorrect.

@CoBB: I think I know what you're going to say, but I'd feel better if I understood what was going on here rather than copying and pasting another solution. :)
Last edited by benryves on Tue 21 Nov, 2006 12:38 pm, edited 1 time in total.
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

You know what I just found out..
XOR seems to SET the P/V flag no matter what..
that's really odd..
AND: reset if parity even, set otherwise
OR: same as AND

program used:

Code: Select all

                ld a,some number
		xor/or/and a
		jp po,RESET
		call disp
		.db "P/V set!",0
		ret
RESET:
		call disp
		.db "P/V RES!",0
		ret
disp:
	pop hl
	bcall(_PutS)
	jp (hl)
I hope I didn't make any serious mistakes there lol :P
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Strange - what happens if you compare

Code: Select all

    ld a,0
    xor 0
...and...

Code: Select all

    ld a,1
    xor 0
?
Anyhow, it's my implementation of overflow that's more the issue, not parity. :)
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

Code: Select all

    ld a,1
    xor 0
gives P/V reset,

Code: Select all

    ld a,0
    xor 0
gives P/V set

I'll also try out some "add"s that will result in overflow
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

Code: Select all

		ld a,$FA
		sub $F0
P/V RES

Code: Select all

		ld a,$FA
		add a, $F0
P/V RES

Code: Select all

		ld a,$0A
		add a, $A0
P/V RES
starting to get odd, does the P/V flag really represent overflow?
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

As far as my understanding goes, this should cause overflow:

Code: Select all

    ld a,120
    add a,10 ; 130 > 127, overflow
This is what I'm asking, really.
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

Ohh yea signed..
well 120 + 10 set the P/V flag..
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

That’s the point. Overflow is defined on purely signed arithmetic (i.e. the operands are treated as signed numbers and the result must remain between -128 and 127 for no overflow to occur). If you want unsigned overflow, there’s the carry flag already.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

So, the two operands are both treated as signed bytes, then added (or subtracted)? If it's adc/sbc and the carry is set, the signed result is shunted one extra value up (adc) or down? (sbc)?

I'm sure I've tried it like that, so it could be I have a bug elsewhere...
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

Yes, that’s how it works. Try to generate a full table using your formula and see where it diverges from the correct values. That’s how I could figure out how DAA works.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

I've been saving daa for last, and that's the only one (or at least, its associated group) that's still failing beyond aluop. :)

The other possibility is that the emulation is so broken that ZEXALL has been calculating and comparing CRCs incorrectly all along, and so aluop is the only one that's implemented correctly and all the others have been failing...

(The link in the signature shows what this is in aid of).
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Hm, I think there's something slightly more seriously wrong. Everything passes ZEXALL, even "aluop a,nn" and "aluop a,<(ix+1),(iy+1)>" - but "aluop a,<ixh,ixl,iyh,iyl>" and "aluop a,<a,b,c,d,e,h,l,(hl)>" fail. They're the only two.

Thanks for the help!
Post Reply