Synthesizing Multibyte NEG
on 6809
(Applies to 6800 and
6801)
(and 6805, with modifications, but we won't talk about that)
The fact that the NEGD routine effectively
does not change
from
the 6800
to
the 6809
had me looking at the 68000's NEGX instruction and NOT instruction and
scratching my head as to why there was no NOTX instruction and the reasons for
the rules for generating the X bit for the NEG, NEGX, and NOT instructions,
and I started losing confidence in the NEGation sequence I have been using in
my 6800/6801 and 6809 work:
NEGAB COMA ; 2's complement NEGate is bit COMplement + 1
NEGB
BNE NEGABX ; or BCS. but BNE works -- extends 0
INCA
NEGABX RTS
The theory is pretty straightforward. Radix complement negation is to subtract the number from the radix (or radix raised to the power of the number of columns) and remember your borrow (carry).
Bit complement is 1's complement, or reduced radix complementr.
So 2's complement is 1's complement plus 1.
And then you just carry any borrow from the first column as far as it carries.
No, there's something wrong with that description, which is what had me going.
I guess it's more accurate to say the lack of carry carries until you get a non-zero column? As soon as you get a carry, everything to the left becomes 1's complement. Because the carry means borrow. And 1 - 1 is zero, but 0 - 1 is 1. Or something.
[JMR202411050852 clarification:]
The carry generated on the NEG instruction in Motorola CPUs is the borrow from the (virtual) subtraction from zero. This is the inverse of the carry from adding one.
When you subtract from zero, there's going to be a borrow for any non-zero operand.
When you add 1 to the 1's complement (bit inverse), the carry is only going to generate when the result of the add is zero -- which is exactly the same as when the argument (operand) is zero.
So when there is no borrow from the NEG is when there is carry from the add, and you can stop when there is no carry from the add, which, for me anyway, confirms the reasoning behind stopping when you no longer get 0 as a result.
[JMR202411050852 clarification end.]
Anyway, I was getting lost in something, so I came up with a little routine to
test every possible result against straight-out subtracting from 0:
org $2000
start ldu #$2100
ldd #$5a5a
std ,--u
ldd #0
std ,--U
std ,--u
testl ldd 2,u
std ,u
ldd #0
subd 2,u
com ,u
neg 1,u
bne testni
inc ,u
testni cmpd ,u
bne teste
ldd #1
addd 2,u
std 2,u
bne testl
std 4,u
nop
nop
teste ldd 4,u
nop
leau 6,u
nop
Set a breakpoint at teste, step through the loop a couple of times, and let it rip, and if the value at the top of the U stack is cleared when you're done, every value worked correctly.
Now, I keep saying something about BCS, so I can test that, as well. Just change the
bne testni
to
bcs testni
and let'r rip again.
And it works.
And som'eres in there, it hit me like the proverbial ton of bricks going down
again, bit complement (1's complement in a binary field) does not carry. So
the NOT instruction is it's own extending form. And, yes, you prime the NEGX
loop on the 68000 with a straight NEG.
... yeah, and I guess I'm not having a smart brain day today or something ...
Well, so, here's a 4-byte negate on 6809:
* negate the 32-bit number on top of stack:
NEG32 COM ,U
COM 1,U
COM 2,U
NEG 3,U
BNE NEG32X
INC 2,U
BNE NEG32X
INC 1,U
BNE NEG32X
INC ,U
NEG32X RTS
It ought to work.
Back to the regularly scheduled programming, as soon as I finish figuring out
what instruction and addressing combinations on the 68000 are relevant to what
I'm demonstrating.
No comments:
Post a Comment