#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
Vorgefundene Kodierung: UTF-8 | 0
|