Saturday, November 2, 2024

ALPP 02-23 -- Synthesizing Multibyte NEGate on 6809 (Applies to 6800 and 6801)

  Synthesizing Multibyte NEG
on 6809
(Applies to 6800 and 6801)

(and 6805, with modifications, but we won't talk about that)

(Title Page/Index)

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.


(Title Page/Index)


 

 

 

 

No comments:

Post a Comment