Source file: /~heha/basteln/Konsumgüter/Kram/2021/fz.zip/ulmuldiv.S

	.global	ulmuldiv,uldiv,ullxul,ulxull
/* UNGETESTET!
typedef struct{unsigned long quot,rem;} uldiv_t;
*/
// Für ATtiny ohne eingebauten Multiplikationsbefehl:
// Multiplikation und Division „in einem Aufwasch“ mit 64-Bit-Zwischenergebnis
// Ohne Rundung; dazu ggf. den Divisionsrest auswerten!
// 1. Argument = Faktor 1	R25:R24:R23:R22
// 2. Argument = Faktor 2			  R21:R20:R19:R18
// 3. Argument = Divisor					    R17:R16:R15:R14
// Return = uldiv_t: Quotient			  R21:R20:R19:R18
//		     Rest	R25:R24:R23:R22
// Versaut: X,Z (stört nur bei Aufruf von Assembler)
// Takte: ≈ 1200
ulmuldiv:
	push	YL	// Rundenzähler
	// 1. Multiplikation
	 movw	XL,r22	// Faktor1 wegschaffen
	 movw	ZL,r24
	 clr	r25	// Ergebnis freimachen (für Produkt = Rest:Quotient)
	 clr	r24
	 clr	r23
	 sub	r22,r22	// löscht C-Flag gleich mit
	 ldi	YL,32
// Faktor1 = 					R21:R20:R19:R18
// Faktor2 = R31:R30:R27:R26 					
// Produkt =		      R25:R24:R23:R22 : R21:R20:R19:R18
0:	 ror	r25	// Produkt High-Teil, C-Flag der Addition einschieben
	 ror	r24
	 ror	r23
	 ror	r22
	 ror	r21	// Produkt Low-Teil = Faktor1
	 ror	r20
	 ror	r19
	 ror	r18
	 brcc	1f	// Faktor1-Bit: Keine Addition wenn gelöscht
	 add	r22,XL	// Faktor2 addieren
	 adc	r23,XH
	 adc	r24,ZL
	 adc	r25,ZH
1:	 dec	YL
	 brne	0b
// Das Produkt liegt (bereits) um 1 Bit nach links geschoben vor, und das Bit 31 ist im C-Flag.
// Damit entfällt das 1. Schieben in der Divisionsroutine, und es wird hineingesprungen.
	pop	YL
	ldi	XL,32	// Faktor2 wird nicht mehr gebraucht
	rjmp	1f

// Divisionsroutine „wie man DIV vom x86 her kennt“ aber ohne Exception (Divisor 0 oder ≥ EDX)
// 1. Argument = Dividend	R25:R24:R23:R22	: R21:R20:R19:R18			(entsprechend EDX:EAX)
// 2. Argument = Divisor					    R17:R16:R15:R14	(entsprechend DIV-Operand)
// Return = uldiv_t: Quotient			  R21:R20:R19:R18			(entsprechend EAX)
//		     Rest	R25:R24:R23:R22						(entsprechend EDX)
// Versaut: XL=0 (für Aufruf von Assembler, für gcc dürfte X und Z zerstört sein)
// Takte: ≈ 700
// Sonderfälle: Bei 0÷0 kommt 0 Rest 0 'raus
// Ist der Dividend zu groß (auch bei ≠0/0) kommt 0xFFFFFFFF Rest irgendwas 'raus
uldiv:
	ldi	XL,32
0:	lsl	r18	// 64 Bit linksschieben
	rol	r19
	rol	r20
	rol	r21
	rol	r22
	rol	r23
	rol	r24
	rol	r25
1:	brcs	2f	// Bei C-Flag immer subtrahieren
	cp	r22,r14	// Subtraktion prüfen
	cpc	r23,r15
	cpc	r24,r16
	cpc	r25,r17
	brcs	3f	// Subtrahend zu groß: Nicht subtrahieren
2:	sub	r22,r14	// Subtraktion ausführen
	sbc	r23,r15
	sbc	r24,r16
	sbc	r25,r17
	ori	r18,1	// Bit 0 setzen
3:	dec	XL
	brne	0b
	ret

// „Asymmetrische“ Multiplikationsroutine, nicht auf Geschwindigkeit getrimmt
// (Für Geschwindigkeit macht man besser eine 64-Bit-Addition in 32 Runden, das braucht 4 weitere Register.)
// 1. Argument = Faktor1	R25:R24:R23:R22	: R21:R20:R19:R18
// 2. Argument = Faktor2					    R17:R16:R15:R14
// Return = Produkt	  Z:X :	R25:R24:R23:R22	: R21:R20:R19:R18
// Versaut: -
// Darf nicht überlaufen! High-Teil geht (in Z:X) „verloren“
// Takte: ≈ 1300
ullxul:
	push	YL	// Rundenzähler
	 clr	ZH
	 clr	ZL
	 clr	XH
	 sub	XL,XL	// löscht C-Flag gleich mit
	 ldi	YL,65	// 1× mehr schieben um C-Flag auszuschieben
0:	 brcc	1f
	 add	XL,r14
	 adc	XH,r15
	 adc	ZL,r16
	 adc	ZH,r17
1:	 ror	ZH	// 96 Bit (!) schieben
	 ror	ZL
	 ror	XH
	 ror	XL
	 ror	r25
	 ror	r24
	 ror	r23
	 ror	r22
	 ror	r21
	 ror	r20
	 ror	r19
	 ror	r18
	 dec	YL
	 brne	0b
	pop	YL
	ret

// „Asymmetrische“ Multiplikationsroutine, schneller als ullxul
// Ein Aufrufmakro muss dafür sorgen, dass der 32-Bit-Faktor1 auf 64 Bit erweitert wird.
// 1. Argument = Faktor1	 0 : 0 : 0 : 0	: R21:R20:R19:R18
// 2. Argument = Faktor2					    R17:R16:R15:R14 : R13:R12:R11:R10
// Return = Produkt	  Z:X :	R25:R24:R23:R22	: R21:R20:R19:R18
// Versaut: -
// Darf nicht überlaufen! High-Teil geht (in Z:X) „verloren“
// Takte: ≈ 800
ulxull:
	push	YL	// Rundenzähler
	 movw	ZL,r26	// Ich verlasse mich darauf, dass Nullen übergeben wurden!
	 movw	XL,r26	// Sonst kommt eh Murks 'raus.
	 clc
	 ldi	YL,33	// 1× mehr schieben um C-Flag auszuschieben
0:	 brcc	1f
	 add	r22,r10
	 adc	r23,r11
	 adc	r24,r12
	 adc	r25,r13
	 adc	XL,r14
	 adc	XH,r15
	 adc	ZL,r16
	 adc	ZH,r17
1:	 ror	ZH	// 96 Bit (!) schieben
	 ror	ZL
	 ror	XH
	 ror	XL
	 ror	r25
	 ror	r24
	 ror	r23
	 ror	r22
	 ror	r21
	 ror	r20
	 ror	r19
	 ror	r18
	 dec	YL
	 brne	0b
	pop	YL
	ret
Detected encoding: UTF-80