I'm completely zombied right now but my earlier effort at least tells me I would expect SUBS and CMPS to set the flags identically. EDIT: Which makes v21 look like an improvement.
I think as long as large number (larger than 32bit) math can be done properly, that is the main thing that matters, right?
That is how I see it. Also, it is important to know after a subtract or a compare if D was less than S. This test is different for signed and unsigned cases. I think that is more important than overflow. Overflow is an error condition that should be designed around, not detected and then dealt with.
I agree about needing to know on compare if D < S, and that is indeed different for signed vs unsigned. I since compare is just subtract with NR, that is why they work the same for flags.
An overflow flag would be nice, but not in some hacky weird way, a proper separate flag. That would require complete reworking of instructions and should absolutely not happen for P2.
I've just been trying to work out how a signed multi-word addition should be managed. I've realised that only the most significant word of the number is actually signed. All lesser significant words of the number are inherently unsigned.
Right again. Once you get to the most significant word you cannot go any higher, which is why using "carry" for signed arithmetic is confusing and wrong. There is nowhere else for a "carry" to go. If the result can't fit, that's an overflow.
...when it indicates that signed D was less than signed S?
It is a signed version of what:
CMP D,S WC
...would return in C, indicating that unsigned D was less than unsigned S.
C after CMPS is what I'd call the "corrected sign" or "correct sign". It is, or should be, the correct sign for the D-S operation, whether or not there has been overflow.
If no overflow, C is the sign bit of the result.
If overflow, C is the negated sign bit of the result.
Chip, could you please confirm this is how your logic works?
The add/subtract logic is the same for unsigned and signed values. Only the C flag is different.
80000000(reg1) - 80000000(reg2) = 00000000
Collected flags = 00000055
CMP reg1,reg2: C = 0, Z = 1
SUB reg1,reg2: C = 0, Z = 1
CMPS reg1,reg2: C = 0, Z = 1
SUBS reg1,reg2: C = 0, Z = 1
7fffffff(reg1) - ffffffff(reg2) = 80000000
Collected flags = 000000a0
CMP reg1,reg2: C = 1, Z = 0
SUB reg1,reg2: C = 1, Z = 0
CMPS reg1,reg2: C = 0, Z = 0
SUBS reg1,reg2: C = 0, Z = 0
ffffffff(reg1) - 7fffffff(reg2) = 80000000
Collected flags = 0000000a
CMP reg1,reg2: C = 0, Z = 0
SUB reg1,reg2: C = 0, Z = 0
CMPS reg1,reg2: C = 1, Z = 0
SUBS reg1,reg2: C = 1, Z = 0
00000004(reg1) - 00000005(reg2) = ffffffff
Collected flags = 000000aa
CMP reg1,reg2: C = 1, Z = 0
SUB reg1,reg2: C = 1, Z = 0
CMPS reg1,reg2: C = 1, Z = 0
SUBS reg1,reg2: C = 1, Z = 0
00000005(reg1) - 00000004(reg2) = 00000001
Collected flags = 00000000
CMP reg1,reg2: C = 0, Z = 0
SUB reg1,reg2: C = 0, Z = 0
CMPS reg1,reg2: C = 0, Z = 0
SUBS reg1,reg2: C = 0, Z = 0
80000000(reg1) - 80000001(reg2) = ffffffff
Collected flags = 000000aa
CMP reg1,reg2: C = 1, Z = 0
SUB reg1,reg2: C = 1, Z = 0
CMPS reg1,reg2: C = 1, Z = 0
SUBS reg1,reg2: C = 1, Z = 0
80000001(reg1) - 80000000(reg2) = 00000001
Collected flags = 00000000
CMP reg1,reg2: C = 0, Z = 0
SUB reg1,reg2: C = 0, Z = 0
CMPS reg1,reg2: C = 0, Z = 0
SUBS reg1,reg2: C = 0, Z = 0
After further thought, the overflow flag is still there in v21, it's just hidden.
MOV D,##$7FFF_FFFF '+2147483647
MOV S,##$FFFF_FFFF '-1
SUBS D,S WCZ 'C is correct sign flag
'D = $8000_0000, C = 0, Z = 0 (NC,NZ)
D[31] = 1, indicating that +2147483647 is less than -1 due to overflow
C = 0, indicating that +2147483647 is not less than -1
C has been corrected to give the right sign for this subtraction, as follows:
C = !D[31] if overflow, else C = D[31]
Let V = 0 if no overflow, V = 1 if overflow, then
C = D[31] XOR V
V = D[31] XOR C
Converting C into V requires one more instruction:
MOV D,##$7FFF_FFFF '+2147483647
MOV S,##$FFFF_FFFF '-1
SUBS D,S WCZ 'C is correct sign flag
TESTB D,#31 XORC 'C is overflow flag
An assembler alias would be handy:
MOV D,##$7FFF_FFFF '+2147483647
MOV S,##$FFFF_FFFF '-1
SUBS D,S WCZ 'C is correct sign flag
TESTV D WC 'C is overflow flag
For ADDS/ADDSX/SUBS/SUBSX:
P1 and P2 v20 and earlier have overflow and extra instruction needed to get sign
P2 v21 has (corrected) sign and extra instruction needed to get overflow
Thanks Tony, I've stepped that through in my head and worked out why Chip has changed it from the Prop1. I'm good with what Chip has logically done in v21. It works cleanly/directly with compares while still having normal unsigned carry from SUB/ADD for extending the numbers.
I like "corrected sign" too. Is a distinct term that won't be confused.
TonyB_, I take it you are okay with the state of things, then?
I think so, Chip. It would be good to have confirmation that TESTB D,#31 XORC does convert C from correct sign to overflow successfully. On September 10th, I wrote:
CMPS/CMPSX is SUBS/SUBSX with the result discarded, so in the former it is safe for C to be something other than overflow. After some study, I think C is simply the sign bit of the result, corrected if there is overflow: C = Sign XOR Overflow.
so I knew then that correct sign should be a function of overflow. Afterwards I did get a bit worked up about what I thought was the total loss of the overflow flag, as I think users should have the ability to test for overflow and I wasn't sure what "signed carry" meant.
Could somebody please try the following? I don't have anything P2, sorry.
'All of the following tests should overflow and set C
MOV FLAGS,#0
'Test 1
MOV D,##$7FFF_FFFF
MOV S,#1
ADDS D,S WCZ 'C is correct sign
TESTB D,#31 XORC 'C is overflow ?
RCZL FLAGS
'is same as
MOV D,##$7FFF_FFFF
MOV S,#1
CMP D,S WZ 'NZ for SUMZ D+S
SUMZ D,S WCZ 'C is overflow
RCZL FLAGS
'Test 2
MOV D,##$8000_0000
MOV S,##$FFFF_FFFF
ADDS D,S WCZ 'C is correct sign
TESTB D,#31 XORC 'C is overflow ?
RCZL FLAGS
'is same as
MOV D,##$8000_0000
MOV S,##$FFFF_FFFF
CMP D,S WZ 'NZ for SUMZ D+S
SUMZ D,S WCZ 'C is overflow
RCZL FLAGS
'Test 3
MOV D,##$8000_0000
MOV S,#1
SUBS D,S WCZ 'C is correct sign
TESTB D,#31 XORC 'C is overflow ?
RCZL FLAGS
'is same as
MOV D,##$8000_0000
MOV S,#1
CMP D,S WZ 'NZ for SUMNZ D-S
SUMNZ D,S WCZ 'C is overflow
RCZL FLAGS
'Test 4
MOV D,##$7FFF_FFFF
MOV S,##$FFFF_FFFF
SUBS D,S WCZ 'C is correct sign
TESTB D,#31 XORC 'C is overflow ?
RCZL FLAGS
'is same as
MOV D,##$7FFF_FFFF
MOV S,##$FFFF_FFFF
CMP D,S WZ 'NZ for SUMNZ D-S
SUMNZ D,S WCZ 'C is overflow
RCZL FLAGS
'FLAGS = %10_10_10_10_10_10_10_10 = $AAAA ?
The result in flags is %10_10_10_10_10_10_10_10, which is what you'd want.
I changed all the $7FFF_FFFF's to $7FFF_FFFE and all the $8000_0000's to $8000_0001 and the result became %00_00_00_00_00_00_00_00, which is also correct.
It never occurred to me use those blasted flag operators to get an overflow indicator. Good thinking!
I was looking for a single instruction to do D[31] XOR C and TESTB almost chose itself. TESTB D,#31 XORC is a bit long-winded, mind you, and the XORC suffix is unfamiliar, which is why I mentioned an alias. TESTB is a great instruction, blessed rather than blasted!
I complained about losing the overflow flag, others said it is not that important and none of us realised that it had not gone away at all. Many thanks for considering my C & Z overflow idea. You politely declined it, which was the right thing to do as your change to ADDS/ADDSX/SUBS/SUBSX is definitely better.
Could "C = correct sign" be adopted officially? It is what it says. No other CPU I know corrects the sign after overflow. It's interesting that detecting overflow after CMPS/CMPSX is impossible, but the only thing that matters here is that the correct sign is reported. This lack of redundancy tells me that v21 is the way the P2 should be.
We've given signed arithmetic a really good examination and all's well that ends well, I think. I just need to edit some posts now and re-write history!
Is there such a thing as overflow when doing CMPS/CMPSX? Because you are just comparing, and not producing a 'difference', I think there's nothing that could be called overflow. Is that right? $8000_0000 compared to $0000_0001 is 'less than', so C=1. I'm a little punch drunk from all this signed stuff.
We could call it "correct sign", but maybe just "sign" would suffice. On the other hand, "correct sign" doesn't get mentally dismissed as easily.
Comments
That is how I see it. Also, it is important to know after a subtract or a compare if D was less than S. This test is different for signed and unsigned cases. I think that is more important than overflow. Overflow is an error condition that should be designed around, not detected and then dealt with.
An overflow flag would be nice, but not in some hacky weird way, a proper separate flag. That would require complete reworking of instructions and should absolutely not happen for P2.
Many thanks for the test results, Evan. No need to do them on a P1.
Correct.
An overflow can occur without a carry from the lower words, e.g. $8000_0000_0000_0000 + $8000_0000_0000_0000.
Right again. Once you get to the most significant word you cannot go any higher, which is why using "carry" for signed arithmetic is confusing and wrong. There is nowhere else for a "carry" to go. If the result can't fit, that's an overflow.
C after CMPS is what I'd call the "corrected sign" or "correct sign". It is, or should be, the correct sign for the D-S operation, whether or not there has been overflow.
If no overflow, C is the sign bit of the result.
If overflow, C is the negated sign bit of the result.
Chip, could you please confirm this is how your logic works?
The add/subtract logic is the same for unsigned and signed values. Only the C flag is different.
With the way it works now, C always holds the sign of the result, even during overflow.
And the new collector code:
EDIT: included code showing equation result at tail of collector code
reg1 = $8000_0000, reg2 = $8000_0001
reg1 = $8000_0001, reg2 = $8000_0000
EDIT:
Numbers changed!
D[31] = 1, indicating that +2147483647 is less than -1 due to overflow
C = 0, indicating that +2147483647 is not less than -1
C has been corrected to give the right sign for this subtraction, as follows:
C = !D[31] if overflow, else C = D[31]
Let V = 0 if no overflow, V = 1 if overflow, then
C = D[31] XOR V
V = D[31] XOR C
Converting C into V requires one more instruction:
An assembler alias would be handy:
For ADDS/ADDSX/SUBS/SUBSX:
P1 and P2 v20 and earlier have overflow and extra instruction needed to get sign
P2 v21 has (corrected) sign and extra instruction needed to get overflow
I like "corrected sign" too. Is a distinct term that won't be confused.
ADD: C = Sm . Dm + Dm . !Rm + Sm . !Rm
+ is OR
. is AND
! is NOT
C is carry flag.
m is most significant bit of the register.
S, D, R are Source, Destination and Result respectively.
That's pretty much verbatim copied from the 68k manual.
ADD:
sum[32:0] = d[31:0] + s[31:0]
c = sum[32]
SUB/CMP:
sum[32:0] = d[31:0] - s[31:0]
c = !sum[32]
ADDS:
sum[32:0] = d[31:0] + s[31:0]
c = sum[32] XOR d[31] XOR s[31]
SUBS/CMPS:
sum[32:0] = d[31:0] - s[31:0]
c = sum[32] XOR d[31] XOR !s[31]
So then you're thinking those XORs change the carry into a valid extended sign bit.
They certainly seem to.
I remember writing down all the cases for 4-bit values, then I saw the pattern.
C for Correct sign (ADDS/SUBS/CMPS)
I think so, Chip. It would be good to have confirmation that TESTB D,#31 XORC does convert C from correct sign to overflow successfully. On September 10th, I wrote:
so I knew then that correct sign should be a function of overflow. Afterwards I did get a bit worked up about what I thought was the total loss of the overflow flag, as I think users should have the ability to test for overflow and I wasn't sure what "signed carry" meant.
Could somebody please try the following? I don't have anything P2, sorry.
Good work!
The result in flags is %10_10_10_10_10_10_10_10, which is what you'd want.
I changed all the $7FFF_FFFF's to $7FFF_FFFE and all the $8000_0000's to $8000_0001 and the result became %00_00_00_00_00_00_00_00, which is also correct.
It never occurred to me use those blasted flag operators to get an overflow indicator. Good thinking!
I was looking for a single instruction to do D[31] XOR C and TESTB almost chose itself. TESTB D,#31 XORC is a bit long-winded, mind you, and the XORC suffix is unfamiliar, which is why I mentioned an alias. TESTB is a great instruction, blessed rather than blasted!
I complained about losing the overflow flag, others said it is not that important and none of us realised that it had not gone away at all. Many thanks for considering my C & Z overflow idea. You politely declined it, which was the right thing to do as your change to ADDS/ADDSX/SUBS/SUBSX is definitely better.
Could "C = correct sign" be adopted officially? It is what it says. No other CPU I know corrects the sign after overflow. It's interesting that detecting overflow after CMPS/CMPSX is impossible, but the only thing that matters here is that the correct sign is reported. This lack of redundancy tells me that v21 is the way the P2 should be.
We've given signed arithmetic a really good examination and all's well that ends well, I think. I just need to edit some posts now and re-write history!
Is there such a thing as overflow when doing CMPS/CMPSX? Because you are just comparing, and not producing a 'difference', I think there's nothing that could be called overflow. Is that right? $8000_0000 compared to $0000_0001 is 'less than', so C=1. I'm a little punch drunk from all this signed stuff.
We could call it "correct sign", but maybe just "sign" would suffice. On the other hand, "correct sign" doesn't get mentally dismissed as easily.
Nice!
Mike
Agreed. I need to look into shortening those instructions by doing something like this with them:
WAIT.... Never mind. Both C and Z can be recipients of the operation, so it needs to stay as it is.
but perhaps a macro could be used?
Good idea!!!!