/*
;;; MULTIPLY SUBROUTINE
;M-1 TIMES Q-R, RESULT TO Q-R, LEAVES CORRECT HIGH HALF IN M-2.
;CALLER MUST CHECK FOR OVERFLOW, IF SHE CARES.

MPY	((M-2) MULTIPLY-STEP A-1 M-ZERO)
(REPEAT 30. ((M-2) MULTIPLY-STEP M-2 A-1))
	(POPJ-IF-BIT-CLEAR-XCT-NEXT (BYTE-FIELD 1 0) Q-R)
       ((M-2) MULTIPLY-STEP M-2 A-1)
	(POPJ-AFTER-NEXT
	 (M-2) M-2 SUB A-1)		;FINAGLE IF NEGATIVE VALUE INITIALLY IN Q-R
       (NO-OP)

       (alu) mult-step a=22 m=2 m[2] C=0 alu>>+s >>Q -><none>,m[23]
       (alu) mult-step a=22 m=23 m[23] C=0 alu>>+s >>Q -><none>,m[23]
       ...
       (jump) a=0 m=Q pc 0, R !jump m-rot<< 0
       (alu) mult-step a=22 m=23 m[23] C=0 alu>>+s >>Q -><none>,m[23]
*/

unsigned int alu_out;
int alu_carry;
int show;

void um(/*unsigned*/ int qr,
	/*unsigned*/ int m1,
	unsigned int *pm2,
	unsigned int *pqr)
{
	int i, do_add;
	unsigned int q, old_q;
	long long lv;
	int a_src_value, m_src_value;
	int carry_in = 0;
	/*unsigned*/ int out_bus;
	int take_jump;
	/*unsigned*/ int m2;
	int oflo;

	q = qr;

	for (i = 0; i < 32; i++) {

		if (i == 0) {
			a_src_value = m1;
			m_src_value = 0;

			printf("top, a %08x (%o), q %08x (%o), m %08x (%o)\n",
			       a_src_value, a_src_value, q, q, 
			       m_src_value, m_src_value);

		} else {
			a_src_value = m1;
			m_src_value = m2;
		}

		/* multiply step */
		/* ADD if Q<0>=1, else SETM */
		do_add = q & 1;

		if (show)
		printf("loop %d, m %08x (%o) alu %08x (%o), q %08x (%o), do_add %d\n",
		       i, m_src_value, m_src_value, alu_out, alu_out, q, q, do_add);

		if (do_add) {
#if 0
			lv = ((/*unsigned*/ long long)a_src_value) +
				m_src_value +
				(carry_in ? 1 : 0);
			alu_out = lv;
			alu_carry = (lv >> 32) ? 1 : 0;
			printf("lv %16llx, ", lv);
#else
			alu_out = a_src_value + m_src_value + (carry_in ? 1 : 0);
		alu_carry = carry_in ?
			( a_src_value >= ~m_src_value ? 0 : 1 ) :
			( a_src_value > ~m_src_value ? 0 : 1 );
#endif
		} else {
			lv = m_src_value;
			alu_out = m_src_value;
			alu_carry = 0;
alu_carry = alu_out & 0x80000000 ? 1 : 0;
		}

if (0) printf("a %o, m %o, ac %d\n", a_src_value, m_src_value, alu_carry);

		/* */
		old_q = q;

		q >>= 1;
		if (alu_out & 1)
			q |= 0x80000000;

		/* */
#if 0
 {
	 int o1, o2, o3, c;
	 o1 = (alu_out & 0x80000000) ? 1 : 0;
	 o2 = ((lv >> 32) & 1) ? 1 : 0;
	 o3 = ((lv >> 33) & 1) ? 1 : 0;
	 c = ( a_src_value > ~m_src_value ? 0 : 1 );
//	 printf("lv %016llx, o %d %d %d c %d ac %d\n", lv, o1, o2, o3, c, alu_carry);
	 alu_carry = c;
 }
#endif

#if 1
		out_bus = (alu_out >> 1) | (alu_carry ? 0x80000000 : 0);
#else
		out_bus = (alu_out >> 1) | (alu_out & 0x80000000);
#endif

if (0)	 printf("out_bus %o, alu_carry %d\n", out_bus, alu_carry);


		/* */
		m_src_value = out_bus;
		m2 = out_bus;

		/* */
		if (i == 31) {
			take_jump = !(old_q & 1);
			if (take_jump) {
				printf("jump; old_q %08x %o\n", old_q, old_q);
				goto done;
			}
		}
	}

	m2 = m2 - m1;

 done:
	printf("done, m2 %08x (%o), q %08x (%o), alu %08x (%o)\n",
	       m2, m2, q, q, alu_out, alu_out);
	
	*pm2 = m2;
	*pqr = q;
}

void
try(int n1, int n2)
{
	unsigned int q, r;
	long long ll1, ll2, ll3;

	ll1 = n1;
	ll2 = n2;
	ll3 = ll1 * ll2;

	printf("\n");
	printf("ll3 %016llx\n", ll3);
	printf("correct: %08x (%o) %08x (%o)\n",
	       (unsigned int)(ll3 >> 32), (unsigned int)(ll3 >> 32),
	       (unsigned int)(ll3), (unsigned int)(ll3));

	um(n1, n2, &q, &r);
}

main()
{
	unsigned int q, r;

#if 0
	show = 0;
	try(0, 1);
	try(1, 1);
	try(2, 1);
	try(2, 2);
	try(2, 3);
	try(3, 9);
	try(012436560510, 014200000000);
#endif
#if 1
	show = 0;
//	try(2, 2);
//	try(012436560510, 014200000000);
//	try(012436560510, 0);
//	try(012436560510, 1);
//	try(012436560510, 2);
//	show = 1;
//	try(012436560510, 01000000000);
//	try(0x40000000, 1);
//	try(0x40000000, 2);
//	try(0x40000000, 4);

//	try(010000000000, 0x8);
//	try(010000000000, 0x80);
//	try(010000000000, 0x800);
//	try(010000000000, 0x8000);
//	try(010000000000, 0x80000);
//	try(010000000000, 0x800000);
//	try(010000000000, 0x8000000);
//	try(010000000000, 010000000000);
//	try(012400000000, 010000000000);
//	try(012436000000, 010000000000);
//	try(012436560510, 010000000000);
//	try(012436560510, 014000000000);
#endif

#if 1
	try(012436560510L, 014200000000L);
	try(012436560510L, 014100000000L);

	try(1, 0);
	try(0, 1);
	try(1, 2);
	try(-1, 2);
	try(1, -2);
	try(-1, -2);
#endif
	try(-1, 01234);
	try(1, -2);
	try(4, -1);
	try(01234, -1);
}
