Source file: /~heha/basteln/PC/FunkUsb/dcf77franz9.zip/check77.S

#define __SFR_OFFSET 0
#include "avr/io.h"
.global incMinute,copyDate,checkConvert,setBit

// Liefert true bei ungerader Parität (__builtin_parity() und "util/parity.h" sind Murks)
// PE: R24 = Byte mit Bits
// PA: R24 Bit 0 = Parität, 1 wenn ungerade. Die anderen Bits sind 0. Z entsprechend gesetzt.
// VR: R25 — wird leider vom gcc-Optimierer nicht beachtet
// b ^= b>>4 | b<<4;	// swap:  x  x  x  x	73   62   51   40
// b ^= b >> 2;		// 2×lsr: x  x  x  x	x    x    5173 4062
// b ^= b >> 1;		// lsr:	  x  x  x  x	x    x    x    40625173
// return b&1;
parity:
	mov	r25,r24
	swap	r25
	eor	r24,r25
	mov	r25,r24
	lsr	r25
	lsr	r25
	eor	r24,r25
	mov	r25,r24
	lsr	r25
	eor	r24,r25
	andi	r24,1
	ret

// Tage eines Monats
// PE: R24 = Monat, 0-basiert, binär
//     R25 = Jahr ohne Jahrhundert, binär
// PA: R24 = Anzahl Tage im Monat
// VR: R25
// if (++u.b[0]==2) return 28+!(u.b[1]&3);
// return 30+((u.b[0]>>3^u.b[0])&1);
tage:
	inc	r24
	cpi	r24,2	// Februar?
	brne	2f
	ldi	r24,28
	andi	r25,3
	brne	1f
	inc	r24	// Schaltjahr
1:	ret
2:	mov	r25,r24
	lsl	r25
	swap	r25
	eor	r24,r25
	andi	r24,1
	subi	r24,-30	// 0xE2
	ret

// „Gepackte“ BCD-Zahl in Binärzahl wandeln, liefert >99 für ungültige Tetraden
// Maximum-Test danach = Prüfung auf Gültigkeit „in einem Rutsch“
// PE: R24 = gepackte BCD-Zahl
// PA: R24 = Binärzahl, >99 bei (ungültigen) Pseudotetraden
// VR: R25
// byte t = b&15;		// Lo-Nibble
// if (t>=10) b=0xA0;	// Pseudotetrade
// b&=0xF0;		// Hi-Nibble
// b>>=1; t+=b; b>>=2; b+=t;	// 10× (b>>4), Compiler stellt sich hier doof an
// return b;
bcd:
	mov	r25,r24		// R0 = 80 40 20 10  8 4 2 1
	andi	r24,15		// R24=  0  0  0  0  8 4 2 1
	eor	r25,r24		// R0 = 80 40 20 10  0 0 0 0
	cpi	r24,10
	brcs	1f
	ldi	r25,160
1:	lsr	r25		// R0 =  0 80 40 20 10 0 0 0
	add	r24,r25
	lsr	r25
	lsr	r25		// R0 =  0 0 0 80 40 20 10 0
	add	r24,r25
	ret

incMinute:
// PE: Z = Zeiger auf <struct DateTime> (byte Minute, Stunde, Wochentag, Tag, Monat, Jahr)
// PA: -
// VR: W,Z
	ldi	r24,60	// Minute bis 59
	rcall	8f
	brcs	9f
	ldi	r24,24	// Stunde bis 23
	rcall	8f
	brcs	9f
	ldi	r24,7	// Wochentag bis 6
	rcall	8f
	ldd	r24,Z+1	// Monat
	ldd	r25,Z+2	// Jahr
	rcall	tage	// Tage des Monats ermitteln
	rcall	8f	// Keine Extrawurst durch Festlegung: Tage beginnen mit 0
	brcs	9f
	ldi	r24,12	// Monat 0..11
	rcall	8f
	brcs	9f
	ldi	r24,100	// Jahr 0..99
8:	ld	r25,Z
	inc	r25
	cp	r25,r24
	brcs	1f
	clr	r25
1:	st	Z+,r25
9:	ret

// byte r=0,m=4;
// do{
//  byte t=*Z++;
//  if (*X!=t) {*X=t; r|=m;}
//  d++;
// }while(m<<=1);
copyDate:
// PE: Z = Quelle: struct DateTime (auch im Flash)
//     X = Ziel: struct DateTime (6 Bytes)
// PA: R24 = Bit 7:2 gesetzt für geänderte Bytes, Bit 1:0 = 0
// VR: R25, R0, R1=0, X, Z
	ldi	r24,0
	ldi	r25,4
0:	rcall	read_byte_pp
	ld	r1,X
	cp	r0,r1
	breq	1f
	st	X,r0
	or	r24,r25
1:	adiw	XL,1
	lsl	r25
	brne	0b
	clr	r1
	ret

// konvertiert DCF77-BCD-Uhrzeit in DateTime-Struktur und meldet Fehler
// PE: Z = Quelle: data[8] (auch im Flash)
//     X = Ziel: struct DateTime
// PA: R23:R22 = Fehlerbits
// VR: W18, W24, X, Z
checkConvert:
	rcall	read_byte_pp	// wl
	ldi	r22,1<<0
	and	r22,r0
	adiw	zl,1		// wh übergehen
	// Info
	rcall	read_byte_pp
	ldi	r24,0x2C
	and	r24,r0
	cpi	r24,0x24
	breq	1f
	cpi	r24,0x28
	breq	1f
	sbr	r22,1<<1
1:	// Minuten
	rcall	read_byte_pp
	mov	r24,r0
	rcall	parity
	mov	r23,r24		// bleibt Bit 0
	mov	r24,r0
	andi	r24,0x7F
	rcall	bcd
	st	X+,r24
	cpi	r24,60
	brcs	1f
	sbr	r22,1<<2
1:	// Stunden
	rcall	read_byte_pp
	mov	r24,r0
	rcall	parity
	lsl	r24		// zu Bit 1
	or	r23,r24		// dazu
	mov	r24,r0
	andi	r24,0x3F
	rcall	bcd
	st	X+,r24
	cpi	r24,24
	brcs	1f
	sbr	r22,1<<3
1:	// Tag + Datumsparität
	rcall	read_byte_pp
	mov	r18,r0	// erst mal retten
	// Wochentag + Monat
	rcall	read_byte_pp
	mov	r19,r0	// erst mal retten
	// Jahr
	rcall	read_byte_pp
	// Z ist jetzt frei
	// Wochentag (ZH) prüfen und ablegen
	mov	ZH,r19	// Wochentag verarbeiten
	andi	ZH,7
	brne	1f
	sbr	r22,1<<4
1:	cpi	ZH,7
	brne	1f
	clr	ZH
1:	st	X+,ZH
	mov	r24,r0
	eor	r24,r18
	eor	r24,r19
	rcall	parity
	lsl	r24
	lsl	r24
	or	r22,r24
	mov	r24,r18
	lsr	r24
	lsr	r24
	rcall	bcd
	dec	r24
	mov	r18,r24	// Tag (R18) jetzt binär
	mov	r24,r0
	rcall	bcd
	mov	ZL,r24	// Jahr (R21) jetzt binär
	mov	r24,r19	// Monat
	lsr	r24
	lsr	r24
	lsr	r24
	rcall	bcd
	dec	r24
	mov	r19,r24	// Monat (R19) jetzt binär
	mov	r25,ZL	// Jahr
	rcall	tage
	// Tag prüfen und ablegen
	cp	r18,r24
	brcs	1f
	sbr	r22,1<<5
1:	st	X+,r18
	// Monat prüfen und ablegen
	cpi	r19,12
	brcs	1f
	sbr	r22,1<<6
1:	st	X+,r19
	// Jahr prüfen und ablegen
	cpi	ZL,100
	brcs	1f
	sbr	r22,1<<7
1:	st	X+,ZL
	// Wochentag prüfen (X ist jetzt frei)
// PE: R18 = Tag, R19 = Monat, ZL = Jahr, ZH = Ist-Wochentag
// PA: R23.3 = Fehler-Bit „Wochentag passt nicht“ (stets im 22. Jahrhundert)
	movw	XL,ZL
	mov	ZL,r19		// Monat
	lsr	ZL		// Nibble adressieren
	clr	ZH
	subi	ZL,lo8(-(mwn))
	sbci	ZH,hi8(-(mwn))
	lpm	r24,Z
	sbrc	r19,0
	 swap	r24		// Lo- oder Hi-Nibble auswählen
	andi	r24,15
	add	r24,r18		// Tag
	cpi	r19,2		// Wenn Januar oder Februar: C = 1
	sbc	XL,r1		// Jahr 'runter
	add	r24,XL
	lsr	XL
	lsr	XL
	add	r24,XL
	ldi	r25,7
	rcall	div88
	cp	XH,r25
	breq	1f
	sbr	r23,1<<3	// „Wochentag falsch“ melden
1:	ret

.type mwn,@common		// nicht disassemblieren
// Nibbleweise Wochen-Modulus pro Monat
mwn:	.byte	0x41,0x63,0x41,0x26,0x05,0x53	// Nur für Jahr 2000..2099!

/*
div168:
// PE:	W24 = Dividend (vzl.)
//	R22 = Divisor (vzl.)
// PA:	W24 = Quotient
//	R22 = Rest
//	R0  = Divisor
	mov	r0,r22
	clr	r22	// Mit Rest=0 anfangen
div248:			// Hier darf der Dividend 24 Bit sein, solange der Quotient in 16 Bit passt. Divisor in R0
0:	lsl	r24
	rol	r25
	rol	r22
	cp	r22,r0
	brcs	1f
	inc	r24
	sub	r22,r0
1:	inc	r1
	sbrs	r1,4
	 rjmp	0b	// 16 Runden (bis Bit 4 gesetzt)
	clr	r1
	ret
*/
div88:
// PE:	R24 = Dividend (vzl.)
//	R25 = Divisor (vzl.)
//	R1  = 0
// PA:	R24 = Quotient
//	R25 = Rest
//	R0  = Divisor
	mov	r0,r25
	clr	r25	// Mit Rest=0 anfangen
0:	lsl	r24
	rol	r25
	cp	r25,r0
	brcs	1f
	inc	r24
	sub	r25,r0
1:	inc	r1
	sbrs	r1,3
	 rjmp	0b	// 8 Runden (bis Bit 3 gesetzt)
	clr	r1
	ret

setBit:
// PE:	X = 64-Bit-Array (max. 256-Bit-Array = 32 Bytes)
//	R24 = Bitnummer
// VR:	R25
	mov	r25,r24
	lsr	r25
	lsr	r25
	lsr	r25
	add	XL,r25
	adc	XH,r1
	ldi	r25,1
	andi	r24,7
	breq	2f
1:	lsl	r25
	dec	r24
	brne	1b
2:	ld	r24,X
	or	r24,r25
	st	X,r24
	ret

Detected encoding: UTF-80