[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: SLC flaws
- To: debate@fitug.de
- Subject: Re: SLC flaws
- From: lutz@iks-jena.de (Lutz Donnerhacke)
- Date: 1 Dec 1999 17:46:14 GMT
- Comment: This message comes from the debate mailing list.
- Newsgroups: iks.lists.fitug
- Organization: IKS GmbH Jena
- References: <19991130173401.A12952@belenus.iks-jena.de>
- Sender: owner-debate@fitug.de
- User-Agent: slrn/0.9.5.7 (UNIX)
* Lutz Donnerhacke wrote:
> Christian Kahlo
> Bemerkungen zur SLE44/66 Familie
> 1999-11-29
Und weiter geht's.
Matthias Brüstle
Commented disassembly of the CMS/RMS for the Siemens SLE44/66
1999-12-01
Abstract
A plain disassembly read from a chip card is commented.
There is also shown a possible attack.
Structure of the CMS/RMS
As is shown in [1] the Chip/Resource Management System (CMS/RMS) is split in
two parts. The first 1kB at the address 0x0000, the second 1kB at the
address 0x4000. In the following I describe only the parts I understood what
they do.
Execution begins at 0x0000. After a normal reset, i.e. with IO pin high it
checks if the card is initialized (0x0047). If it is it jumps to the begin
of the application code at 0x0400. If it is not, it receives an eight byte
key and compares it to the key stored at the last eight bytes of the ROM
(0x43F8). If the key matches it jumps to a command loop in the second halve
of the CMS/RMS (0x403a}). The command loop waits for receiving a byte over
the IO pin. This is used to look up one of 29 function pointers in a table
at 0x4000. This function is then executed. Functions which purpose are
known are shown in table 1.
Table 1: Known functions executable by the CMS/RMS
Address | Function
-----------------------------------------------
0x00DA | Erase and write to EEPROM
0x02F0 | Execute application
0x406F | Set special function registers (SFR)
0x410C | Set processor status word (PSW)
0x41B1 | Write to RAM
0x41E4 | Read from RAM
0x41F0 | Read from ROM/EEPROM
0x4219 | Execute code in ROM/EEPROM
As written in [1] if the IO pin is low at a reset the first 16 bytes of the
EEPROM are sent through the IO pin. The code executed after this needs
further studying.
Attacks
To get by normal execution of the CPU into the command loop there are two
requirements:
1. At the start of the EEPROM some bytes have to have specific values.
(0x8000: 0xA9, 0x8004--6: 0x99, 0x60, 0x19)
2. The mask key must be known.
In issued cards requirement 1 is not met, because the byte at 0x8000 is
0x33. To fulfill this requirement it could be either this byte modified with
an intrusive physical attack or conditional jumps/calls must be modified by
a power or clock glitch [2]. The second method has to modify instructions at
0x0048 or 0x0053 and at 0x404b.
Requirement 2 is probably easier met because many cards share the same mask
key. To read out the mask key a differential power analysis [3] could be
applied while at key is compared at 0x0319 or the key could be read out by
an intrusive physical attack and used on any other card sharing the same
key. The feasibility of all these attacks is unknown. Requirement 2 can also
be easily met by the issuer of the card.
Conclusions
Never trust anything.
Bibliography
[1] Kahlo, C.; {Bemerkungen zur SLE44/66 Familie}; Jena; 1999;
news:slrn8480js.cna.lutz@belenus.iks-jena.de
[2] Anderson, R.; Kuhn, M. G.; {Tamper Resistance - a Cautionary Note},
In Proceedings of the 2nd. Workshop On Electronic Commerce;
USENIX Association: Oakland, 1996; pp 1-11;
http://www.cl.cam.ac.uk/~mgk25/tamper.html
[3] Kocher, P.; Jaffe, J.; Jun, B.; {Differential Power Analysis};
http://www.cryptography.com/dpa/Dpa.pdf
Appendix A: Commented disassembly of the CMS/RMS
; Commented 8051 Disassembly of 44C80S Chip Management System
;
; ADRXH(0b3h): Contains the hight byte of the address used in
; EEPROM writes.
; EETIME(0bdh): Timings for EEPROM writes.
; EECTRL(0d8h):
; EEPAGE(0fbh):
; p1.0(090h): IO pin.
; 094h.0(094h): Direction of IO (0: receive, 1: send).
; rb1r0(08h): Used to store 0x43 after the verification of the
; mask key.
;
org 0
;
X0000: clr a ; a = 0
mov adrxh,#80h ; [0xB3] = 0x80
mov r1,a ; r1 = 0
mov eetime,#31h ; [0xBD] = 0x31
mov 0fdh,#0dch ; [0xFD] = 0xDC
acall X03a4 ; Wait dependant on psw.1
jb p1.0,X0045 ; if( p1.0 ) init and call ROM application
; Send 16 bytes starting at external [0x8000].
movx a,@r1 ; \
mov r6,a ; / r6 = external [0x8000]
mov r2,#10h ; r2 = 0x10
acall X03a4 ; Wait dependant on psw.1
sjmp X0019 ;
X0018: movx a,@r1 ; a = external [0x8000...]
X0019: acall X03e2 ; Send byte (0x437d).
inc r1
djnz r2,X0018 ; Loop 16 times
cjne r6,#33h,X0030 ; if( ext[0x00] != 0x33 ) jump to 0x0030
mov dptr,#X8003 ; dptr = 0x8003
movx a,@dptr ; a = [dptr]
cpl a ; a = ~a;
mov r0,#30h ; r0 = 0x30
mov @r0,a ; [r0] = a;
acall X003c
mov 088h,#44h ; [0x88] = 0x44 (Probably not TCON)
acall X03e2 ; Send byte (0x437d).
X0030: acall X03c8 ; Check if p1.6 can be set and cleared.
X0032: jnc X0032 ; Wait forever if p1.6 cant be toggled.
lcall X4113
lcall X411b
X003a: sjmp X003a ; Wait forever
;
X003c: setb eectrl.2 ; Set [0xD8].2
push b ; Save b
mov b,r2 ; b = r2 (=0)
X0042: inc r2 ; r2++
ajmp X0133
;
X0045: acall X03c8 ; Check if p1.6 can be set and cleared.
movx a,@r1 ; a = ext[r1(=0)]
cjne a,#33h,X0055 ; if( ext[r1]!=0x33 ) goto X0055
mov r1,#4 ; r1 = 4
movx a,@r1 ; a = ext[4]
cjne a,#0ffh,X003a ; if( ext[4]!=0xFF ) goto Wait forever
acall X00a1 ; ext[0x8003]->[0xBD], ext[0x8007]->[0xFD]
ajmp X0400 ; Jump to ROM application.
;
X0055: inc sp ; sp++
cjne a,#0a9h,X0069 ; if( a!=0xa9 ) goto X0069
acall X02d7 ; Check security area
acall X00a1 ; ext[0x8003]->[0xBD], ext[0x8007]->[0xFD]
acall X0084 ; receive and copy 8 bytes
X0060: mov r2,#40h ; r2 = 0x40
mov a,@r0 ; a = [r0]
X0063: acall X02f7
djnz r3,X0060 ; Loop r3 (=8?) times
sjmp X007f ; Compare mask key and jump to command loop
;
X0069: acall X03c8 ; Check if p1.6 can be set and cleared.
X006b: jnc X006b ; if( p1.6 cant be toggled ) Wait forever
mov 2fh,#31h ; [0x2F] = 0x31
X0070: clr a ; a = 0
lcall X42e9
acall X0084 ; Receive and copy 8 bytes
X0076: mov r2,#40h ; r2 = 0x40
movx a,@r0 ; a = ext[r0]
cpl a ; a = ~a
add a,@r0 ; a += int[r0]
acall X02f7
djnz r3,X0076 ; Loop r3 (=8?) times
X007f: acall X0319 ; Compare mask key
ljmp X403a ; Command loop
;
; Receive and copy 8 bytes
X0084: mov r3,#8 ; r3 = 8
mov r1,#30h ; r1 = 0x30
acall X00ce ; Receive 8 bytes to r1
mov r3,#8 ; r3 = 8
X008c: mov a,@r0 ; \
mov @r1,a ; ) Copy 8 bytes from [r0] to [r1]
inc r0 ; ) (r0 should be here the same as r1)
inc r1 ; )
djnz r3,X008c ; /
mov r1,#30h ; r1 = 0x30
mov dptr,#X0000 ; dptr = 0x0000
mov adrxh,#80h ; [0xB3] = 0x80
mov r3,#8 ; r3 = 8
mov b,@r1 ; b = [0x30]
setb eectrl.7 ; setb [0xD8].7
ret
;
; ext[0x8003]->[0xBD], ext[0x8007]->[0xFD]
X00a1: mov r1,#3 ; r1 = 3
movx a,@r1 ; a = ext[0x8003]
mov eetime,a ; [0xBD] = ext[0x8003]
mov r1,#7 ; r1 = 7
movx a,@r1 ; a = ext[0x8007]
mov 0fdh,a ; [0xFD] = ext[0x8007]
ret
;
; Erase and write 1 byte.
; source: a
; destination: dptr
X00ac: mov r7,a ; r7 = a \
mov a,psw ; a = psw ) Copy a to r7 and set r0 to
anl a,#18h ; a &= 0x18 ) the address of r7.
orl a,#7 ; a |= 7 )
mov r0,a ; r0 = a /
mov r2,#1 ; r2 = 1
sjmp X00f2 ; Erase and write n bytes.
;
; Erase and write 4 bytes.
; source: @r0
; destination: @dptr
X00b8: mov r2,#4 ; r2 = 4
anl dpl,#0fch ; dpl &= 0xFC (mask out lower two bits)
sjmp X00f2 ; Erase and write n bytes.
;
; Erase and write n bytes somehow.
; source: @r0
; destination: @dptr
; length: r2
X00bf: mov a,#0c4h ; a = 0xC4 (Sets flags for write procedure)
sjmp X00f3 ; Erase and write n bytes.
;
; Erase and write n bytes somehow.
; source: @r0
; destination: @dptr
; length: r2
X00c3: mov a,#40h ; a = 0x40 (Sets flags for write procedure)
sjmp X00f3 ; Erase and write n bytes.
;
; Read dptr and a bytes.
; Returns r0 with the address of received data and r0 with the number
; of bytes received.
X00c7: mov r3,a ; r3 = a
mov b,a ; b = a
acall X02a8 ; Read 3 bytes, set dptr and return last byte.
sjmp X00d1 ; Read a-1 bytes to r1
;
; Receive r3/b bytes.
; Returns r0 with the address of received data and r0 with the number
; of bytes received.
X00ce: lcall X43b3 ; Receive byte
X00d1: mov @r1,a ; [r1] = a
inc r1 ; r1++
djnz r3,X00ce ; Loop r3 times
mov r2,b ; r2 = b
mov r0,#30h ; r0 = 0x30
X00d9: ret
;
; Erase and write data in EEPROM.
; (Called from fptr table at 0x4000.)
X00da: acall X03e5 ; Check if key checked and receive byte.
acall X00c7 ; Receive dptr and byte1 bytes
mov a,dph ; a = dph
cjne a,#80h,X00ed ; if( dph!=0x80 ) goto X00ed
mov a,dpl ; a = dpl
jnz X00ed ; if( dpl!=0 ) foto X00ed
mov 37h,0fdh ; [0x37] = [0xFD] \ Only when dptr==0x8000
mov 38h,#72h ; [0x38] = 0x72 /
X00ed: mov r1,rb1r0 ; r1 = 0x43 (from dph)
X00ef: cjne r1,#43h,X00ef ; if( r1!=0x43 ) wait forever (key not checked)
; Erase and write n bytes.
; source: @r0
; destination: @dptr
; length: r2
X00f2: clr a ; a = 0
X00f3: xch a,r2 ; swap a and r2
jz X00d9 ; if( a==0 ) ret (no data received)
xch a,r2 ; restore a and r2
setb eectrl.2 ; Set [0xD8].2
push b ; Save b (data length?)
mov b,a ; b = a
mov adrxh,#80h ; [0xB3] = 0x80
mov r1,#0 ; r1 = 0
movx a,@r1 ; a = ext[r1(=0)]
cjne a,#33h,X0123 ; if( a!=0x33 ) goto 0x0123
mov r1,#7 ; r1 = 7
movx a,@r1 ; a = ext[r1(=7)]
mov 0fdh,a ; [0xFD] = ext[r1(=7)]
mov a,dph ; a = dph
cjne a,#80h,X012a ; if( dph!=0x80 ) goto 0x12a
mov a,dpl ; a = dpl
cjne a,#20h,X0115 ; \
X0115: jnc X0133 ; / if( dpl>=0x20 ) goto 0x0133
jnb acc.4,X0121 ; if( !acc.4 ) goto X0223
nop
nop
nop
setb b.2 ; set b.2
sjmp X0135 ; goto X0135
X0121: ajmp X0223 ; goto X0223
X0123: mov r1,rb1r0 ; r1 = 0x43 (from dph)
X0125: cjne r1,#43h,X0125 ; if( r1!=0x43) loop forever (no key checked)
sjmp X0133 ; goto X0133
X012a: jc X0121 ; if( c ) goto X0223 (dph<0x80)
subb a,#80h ; a -= 0x80
cjne a,0fah,X0131 ; \
X0131: jnc X0121 ; / if( a>=[0xFA] ) goto X0223
X0133: mov c,b.6 ; c = b.6
X0135: orl eectrl,#81h ; [0xD8] |= 0x81
mov a,r0 ; a = r0
mov r1,a ; r1 = r0
mov a,r2 ; a = r2
mov r3,a ; r3 = r2
X013c: movx a,@dptr ; a = ext[dptr]
xrl a,@r1 ; \
anl a,@r1 ; / a = (a ^ [r1]) & [r1]
addc a,#0ffh ; a += 0xFF + c (c set if at least once a!=0)
inc dptr ; dptr++
inc r1 ; r1++
djnz r3,X013c ; Loop r3 times
clr a ; a = 0
mov acc.5,c ; acc.5 = c
anl c,/b.2 ; c &= !b.2
mov b.2,c ; b.2 = c
add a,#20h ; a = 0x20
xch a,dpl ; swap a and dpl
subb a,r2 ; dpl -= r2
xch a,dpl ; swap a and dpl
jnc X0157 ; \
dec dph ; / dph -= c
X0157: xrl a,#60h ; a ^= 0x60
; Write n bytes?
X0159: xch a,r0 ; \
mov r1,a ; ) r1 = r0
xch a,r0 ; /
X015c: jbc eectrl.3,X015c ; if( [0xD8].3 ) loop forever
xch a,eectrl ; swap a and [0xD8]
jnb acc.2,X0121 ; if( !acc.2 ) goto X0223
mov a,eepage ; a = [0xFB]
cpl a ; a = ~a
inc a ; a++
orl a,dpl ; a |= dpl
cpl a ; a = ~a
mov r3,a ; r3 = a
inc r3 ; r3++
cpl a ; a = ~a
add a,r2 ; a += r2
jc X0174 ; if( c ) goto X0174
mov a,r2 ; \
mov r3,a ; / r3 = r2
clr a ; a = 0
X0174: mov r2,a ; r2 = a
jb b.1,X0180 ; if( b.1 ) goto X0180
X0178: mov a,@r1 ; a = [r1]
movx @dptr,a ; ext[dptr] = a
inc r1 ; r1++
inc dptr ; dptr++
djnz r3,X0178 ; Loop r3 times
sjmp X018a ; goto X018a
X0180: clr c ; Clear c
X0181: mov a,@r1 ; a = [r1]
jc X0185 ; if( c (every second interation) ) goto X0185
movx @dptr,a ; ext[dptr] = a
X0185: cpl c ; Toggle c
inc r1 ; r1++
inc dptr ; dptr++
djnz r3,X0181 ; Loop r3 times
X018a: jnb eectrl.4,X0199 ; if( ![0xD8].4 ) goto X0199
jnb b.3,X0199 ; if( !b.3 ) goto X0199
clr a ; a = 0
xch a,r1 ; swap a and r1
mov r3,a ; r3 = a
mov adrxh,#80h ; [0xB3] = 0x80
movx a,@r1 ; a = ext[r1]
xch a,r3 ; swap a and r3
mov r1,a ; r1 = a (=restore r1)
X0199: setb eectrl.0 ; Set [0xD8].0
mov a,eetime ; a = [0xBD]
rrc a ; Rotate right a into c
rrc a ; Rotate right a into c
anl a,#3fh ; a &= 0x3F
addc a,#0fch ; a += 0x0F + c
jc X01a6 ; if( c ) goto X01a6
clr a ; a = 0
X01a6: inc a ; a++
mov adrxh,a ; [0xB3] = a
setb eectrl.1 ; Set [0xD8].1
mov a,0fdh ; a = [0xFD]
jnb eectrl.6,X01b1 ; if( ![0xD8].6 ) goto X01b1
swap a ; swap nibbles of a
X01b1: add a,#0fdh ; a += 0xFD
anl a,#0fh ; a &= 0x0F
jz X01c0 ; if( a==0 ) goto X01c0
X01b7: dec a ; a--
mov r3,adrxh ; r3 = [0xB3]
X01ba: djnz r3,X01ba ; Wait dependant on r3
inc eectrl ; [0xD8]++
jnz X01b7 ; if( a!=0 ) goto X01cb
X01c0: jb b.4,X01cb ; if( b.4 ) goto X01cb
mov a,eetime ; a = [0xBD]
jb eectrl.6,X01ca ; if( [0xD8].6 ) goto X01ca
clr c ; Clear c
rrc a ; Rotate right a into c
X01ca: dec a ; a--
X01cb: mov r3,#20h ; r3 = 0x20
X01cd: djnz r3,X01cd ; Wait dependant on r3
jnz X01ca ; if( a!=0 ) goto X01ca
mov a,#84h ; a = 0x84
xch a,eectrl ; swap a with [0xD8]
anl a,#0f0h ; a &= 0xF0
jz X01e4 ; if( a==0 ) goto X01e4
jb acc.4,X01e4 ; if( acc.4 ) goto X01e4
xch a,r2 ; \
jz X01e5 ; ) if( r2==0 ) goto X01e5
xch a,r2 ; /
ajmp X015c ; goto X015c
X01e2: ajmp X0157 ; goto X0157
X01e4: mov r2,a ; r2 = a
X01e5: mov a,r0 ; a = r0
xch a,r1 ; swap a and r1
clr c ; Clear c
subb a,r0 ; a -= r0
mov r3,a ; r3 = a
xch a,r2 ; swap a and r2
X01eb: jbc eectrl.3,X01eb ; if( [0xD8].3 ) clear [0xD8].3, goto X01eb
xch a,dpl ; \
clr c ; ) dpl -= r2
subb a,r2 ; )
xch a,dpl ; /
jnc X01f8 ; \
dec dph ; / dph -= c
X01f8: jbc b.2,X01e2 ; if( b.2 ) clear b.2, goto X01e2
jb eectrl.0,X021c ; if( [0xD8].0 ) goto X021c
jnb acc.4,X020a ; if( !acc.4 ) goto X020a
mov eectrl,#50h ; [0xD8] = 0x50
movx @dptr,a ; ext[dptr] = a
setb eectrl.0 ; set [0xD8].0
mov eectrl,#84h ; [0xD8] = 0x84
X020a: push dpl ; save dpl
X020c: movx a,@dptr ; a = ext[dptr]
inc dptr ; dptr++
djnz r3,X020c ; Loop r3 times
clr eectrl.4 ; clear [0xD8].4
setb eectrl.1 ; Set [0xD8].1
pop dpl ; Restore dpl
jnc X0223 ; if( !c (from inc dptr) ) goto X0223
dec dph ; dph--
sjmp X0223 ; goto X0223
X021c: mov a,eetime ; a = [0xBD]
clr c ; Clear c
rrc a ; Rotate right a into c
mov r3,a ; r3 = a
X0221: djnz r3,X0221 ; Wait dependant on r3
X0223: mov a,#55h ; a = 0x55
jb b.5,X0247 ; if( b.5 ) goto X0247
jb b.7,X0235 ; if( b.7 ) goto X0235
X022b: movx a,@dptr ; a = ext[dptr]
xrl a,@r1 ; a ^= [r1]
jnz X0244 ; if( [r1]!=ext[dptr] ) goto X0244
inc r1 ; r1++
inc dptr ; dptr++
djnz r2,X022b ; Loop r2 times
sjmp X023d ; goto X023d
X0235: movx a,@dptr ; a = ext[dptr]
cpl a ; a = ~a
jnz X0244 ; if( a!=0 ) goto X0244
inc r1 ; r1++
inc dptr ; dptr++
djnz r2,X0235 ; Loop r2 times
X023d: cpl eectrl.0 ; Toggle [0xD8].0
clr eectrl.1 ; Clear [0xD8].1
jb eectrl.0,X01e5 ; if( [0xD8].0 ) goto X01e5
X0244: xch a,r1 ; \
mov r0,a ; ) swap r0 and r1
mov a,r1 ; /
X0247: mov eectrl,#0 ; [0xD8] = 0
pop b ; Restore b
ret
;
; (Called from fptr table at 0x4000.)
X024d: acall X02a6 ; Read 4 B, set dptr, return last Byte
X024f: mov r2,eepage ; r2 = [0xFB]
X0251: xch a,r2 ; \
mov r3,a ; ) r3 = r2
xch a,r2 ; /
X0254: mov @r1,a ; \
inc r1 ; ) copy a r3 times to [r1++]
djnz r3,X0254 ; /
X0258: setb eectrl.2 ; Set [0xDB].2
push b ; Save b
mov b,#20h ; b = 0x20
mov c,2fh.7 ; c = Saved [0xD8].7 (->X02d0)
mov b.2,c ; b.2 |= c
mov adrxh,#80h ; \
mov r0,#0 ; ) a = xternal [0x8000]
movx a,@r0 ; /
cjne a,#0a9h,X0299
setb b.3 ; Set b.3
X026e: mov r0,#30h
mov a,2fh
jnc X027a
cjne a,#31h,X027a
jbc acc.0,X0297
X027a: anl a,#70h
cjne a,#70h,X0283
clr acc.5
setb b.4
X0283: jnb 2fh.3,X0288
setb acc.7
X0288: jnb 2fh.2,X028d
setb b.1
X028d: jnb 2fh.1,X0292
clr b.5
X0292: mov r1,rb1r0 ; r1 = 0x43 (from dph)
X0294: cjne r1,#43h,X0294 ; Loop forever if master key was not checked.
X0297: ajmp X0159 ; Write n bytes?
X0299: acall X03c8 ; Check if p1.6 can be set and cleared.
jc X026e
sjmp X0247
;
; (Called from fptr table at 0x4000.)
X029f: acall X02a6 ; Read 4 B, set dptr, return last Byte
mov r2,a ; r2 = a
acall X03e5 ; Check if key checked and receive byte.
sjmp X0251
;
; Read 4 bytes from IO, set dptr and return last byte.
X02a6: acall X02b7 ; Read byte and do magic with [0xD8].
X02a8: mov r1,#30h ; r1 = 0x30
acall X02ae ; Read dptr from IO.
ajmp X03e5 ; Check if key checked and receive byte.
;
; Read dptr from IO.
X02ae: acall X03e5 ; Check if key checked and receive byte.
mov dph,a ; dph = a
acall X03e5 ; Check if key checked and receive byte.
mov dpl,a ; dpl = a
ret
;
; Read byte and do magic with [0xD8].
X02b7: acall X03e5 ; Check if key checked and receive byte.
X02b9: rl a ; \
cjne a,#20h,X02bd ; ) (a&0x7F) < 0x10 ?
X02bd: rr a ; /
jnc X02d0 ; jump if above is false
mov eectrl,#84h ; [0xD8] = 0x84
anl a,#83h ; a &= 0x83
xch a,eectrl ; swap a, [0xD8]
jb acc.2,X02cf ; if( [0xD8].2 ) jump to ret
X02ca: mov eectrl,#80h ; [0xD8] = 0x80
clr eectrl.7 ; [0xD8].7 = 0
X02cf: ret
X02d0: mov 2fh,a ; Copy a to bit addressable space.
ret
;
; Loop, if p1.6 can be set and cleared. Return in a.
; (Called from fptr table at 0x4000.)
X02d3: acall X03c8 ; Check if p1.6 can be set and cleared.
rlc a
ret
;
; Checks if security area is initalized.
X02d7: mov dptr,#X8000 ; Load DPTR with start address of security area.
movx a,@dptr
X02db: cjne a,#0a9h,X02db ; Loop forever if 0x8000 is not 0xA9.
mov dptr,#X8004 ; (Code byte)
movx a,@dptr
X02e2: cjne a,#99h,X02e2 ; Loop forever if 0x8004 is not 0x99.
inc dptr ; (Internal controll byte)
movx a,@dptr
X02e7: cjne a,#60h,X02e7 ; Loop forever if 0x8005 is not 0x60.
inc dptr ; (Internal controll byte)
movx a,@dptr
X02ec: cjne a,#19h,X02ec ; Loop forever if 0x8006 is not 0x19.
ret ; (Internal controll byte)
;
; Call ROM application.
; (Called from the fptr table at 0x4000.)
X02f0: setb p1.0 ; Set IO high.
mov 94h,#40h ; Set 94h.6
ajmp X0400 ; Jump to ROM application.
;
X02f7: mov @r0,#0ffh ; [r0] = 0xFF
xch a,r3 ; \
jnb acc.0,X02ff ; ) if( r3.0 ) [0xb3]++
inc adrxh ; )
X02ff: xch a,r3 ; /
inc r0 ; r0++
X0301: mul ab ; ba = a*b
xrl a,@r1 ; \
mov @r1,a ; ) [r1++] ^= a
inc r1 ; /
cjne r1,#38h,X030a ; \ if( r1==0x38 ) r1=0x30
mov r1,#30h ; /
X030a: mov a,b ; a = b
mov b,@r1 ; b = [r1]
xrl a,@r1 ; a ^= [r1]
mov @r1,a ; [r1] = a ([r1]^=b)
jnb acc.5,X0315 ; \ if( acc.5 ) {
inc dptr ; ) dptr++; a=0;
clr a ; / }
X0315: movc a,@a+dptr ; a = [dptr+a]
djnz r2,X0301 ; Loop r2 times
ret
;
; Compare mask key
X0319: mov dptr,#X43f8 ; Setup mask key pointer
mov rb1r0,dph ; Save dph to r0 at register bank 1.
clr eectrl.7 ; Clear bit D8h.7
mov r2,#8
X0323: clr a
movc a,@a+dptr ; \ a = [dptr++]
inc dptr ; / [dptr]=21 c0 35 08 81 db d5 08
xrl a,@r1
inc r1
addc a,#0ffh
xrl rb0r3,a ; r3@rb0 ^= a (r3@rb0 should be 0 at the end)
djnz r2,X0323 ; Loop 8 times
cpl c ; c is now set only if all 8 bytes matched
jbc cy,X0335 ; Jump if c, c=0
X0332: ljmp X0000 ; Start if not all 8 bytes matched
X0335: jc X0332 ; Protection to get over jbc by a power glitch?
mov a,r3
jnz X0332 ; Start if r3!=0
inc a
jz X0332 ; Start if r3==0xFF
ret
;
; Receive byte through p1.0 and write it into a and set c if there
; was an error.
; Call at X034a: 9600bps@3.57MHz
; Call at X0348: 9600bps@4.91MHz
X033e: jb p1.0,X033e ; Wait for p1.0==0. (Startbit)
acall X03c6 ; NOP function
acall X03c6 ; NOP function
nop
ajmp X034a
X0348: setb psw.1 ; Set psw.1
X034a: clr f0 ; Clear f0
mov r0,#9
acall X038a ; Read 2 out of 3 of p1.0 (Startbit)
jnc X0354 ; \
setb f0 ; / if( c ) f0=1;
X0354: rrc a ; Rotate right a into carry, i.e. carry into a
acall X03ac ; Wait dependant on psw.1
acall X038a ; Read 2 out of 3 of p1.0 (Byte and Parity)
djnz r0,X0354 ; Loop 9 times
jc X0361 ; \
orl c,p ; ) Set c if there was a parity error.
sjmp X0365 ; )
X0361: anl c,/p ; /
nop ; Delay
nop ; Delay
X0365: orl c,f0 ; c = c | f0
anl psw,#0ddh ; Clear f0 and psw.1
ret
;
; Send byte a including startbit and parity through p1.0
; Call at X036d: 9600bps@4.91MHz
; Call at X036b: 9600bps@3.57MHz
X036b: setb psw.1 ; Set psw.1
X036d: orl 94h,#1 ; Set 94h.0
mov r0,#9
mov c,p ; Set carry to the parity of a
clr p1.0 ; Clear p1.0 (Startbit)
inc r7 ; NOP?
dec r7 ; NOP?
X0378: acall X03a1 ; Wait dependant on psw.1
rrc a ; Rotate a right into carry
mov p1.0,c ; Write c to p1.0 (Byte and Parity)
djnz r0,X0378 ; Loop 9 times
acall X03a1 ; Wait dependant on psw.1
swap a ; Swap nibbles in a
setb p1.0 ; Set p1.0 (Stopbits?)
anl 94h,#0feh ; Clear 94h.0
clr psw.1 ; Clear psw.1
ret
;
; 2 out of 3 of p1.0
X038a: mov r7,#3
mov r2,a ; Save a
clr a
X038e: mov c,p1.0 ; Read p1.0
addc a,#0
jnb psw.1,X0399 ; Delay dependant on psw.1
acall X03c6 ; NOP function
sjmp X039b
X0399: xch a,r0 ; NOP?
xch a,r0 ; NOP?
X039b: djnz r7,X038e ; 3 Loops
mov c,acc.1 ; Set carry if at least 2
mov a,r2 ; Restore a
ret
;
; Wait three times according to psw.1.
X03a1: jnb psw.1,X03a8 ; \
X03a4: mov r7,#1ah ; ) if( psw.1 ) r7=0x1A;
sjmp X03aa ; ) else r7=0x13;
X03a8: mov r7,#13h ; /
X03aa: djnz r7,X03aa ; Waitloop.
X03ac: jnb psw.1,X03b3 ; \
mov r7,#3 ; ) if( psw.1 ) r7=0x03;
sjmp X03b5 ; ) else r7=0x04;
X03b3: mov r7,#4 ; /
X03b5: djnz r7,X03b5 ; Waitloop.
jnb psw.1,X03c2 ; \
mov r7,#0eh ; ) if( psw.1 ) r7=0x0E;
sjmp X03c4 ; ) else r7=0x05;
mov r7,#3 ; \ Dead code
sjmp X03c4 ; /
X03c2: mov r7,#6 ; /
X03c4: djnz r7,X03c4 ; Waitloop.
; NOP function
X03c6: nop
ret
;
; Look, if p1.6 can be set and cleared. Returned in c.
X03c8: orl 94h,#40h
setb p1.6
mov c,p1.6
clr p1.6
anl c,/p1.6
ret
;
nop
nop
nop
nop
nop
nop
nop
nop
nop
;
; (Called from fptr table at 0x4000.)
X03dd: acall X02a8
mov r2,a
ajmp X00bf
;
X03e2: ljmp X437d ; Send byte (0x437d).
X03e5: ljmp X43ae ; Check if key checked and receive byte.
;
; Jump table
X03e8: ret
nop
X03ea: ret
nop
X03ec: ret
nop
X03ee: ajmp X00c3 ; Erase and Write ???
X03f0: ajmp X00f2 ; Erase and Write n bytes.
X03f2: ajmp X033e ; Wait for byte and write it into a.
X03f4: ajmp X00b8 ; Erase and Write 4 bytes. (obsolete)
X03f6: ajmp X00ac ; Erase and Write 1 byte. (obsolte)
X03f8: ajmp X034a ; Receive into a without setting psw.1.
; (9600bps@3.57MHz)
X03fa: ajmp X0348 ; Receive into a with setting psw.1.
; (9600bps@4.91MHz)
X03fc: ajmp X036d ; Transmit a without setting psw.1.
; (9600bps@3.57MHz)
X03fe: ajmp X036b ; Transmit a with setting psw.1.
; (9600bps@4.91MHz)
----- 15 kB USER MASK
; Function pointer table with 29 pointers.
X4000: 42 59 40 65 41 0c 02 f0
X4008: 40 60 03 dd 00 da 02 4d
X4010: 02 9f 43 00 41 69 42 8e
X4018: 42 ae 40 f3 42 db 42 1f
X4020: 41 1b 41 13 41 20 41 7f
X4028: 02 d3 41 b1 41 e4 41 f0
X4030: 42 19 40 6f 40 a6 43 32
X4038: 41 f0
;
; Command loop
X403a: acall X437d ; Send byte (0x437d).
acall X43d2 ; NOP
acall X43ae ; Check if key checked and receive byte.
mov r4,a ; r4=a
cjne a,#1dh,X4044 ; \ if( a>=0x1D ) goto 0x403a
X4044: jnc X403a ; / (Checks for ptr table boundaries.)
lcall X03c8 ; Check if p1.6 can be set and cleared.
jc X404e
lcall X02d7 ; Check security area.
X404e: mov a,r4 ; \ fptr loopup.
mov dptr,#X4000 ; )
rl a ; )
movc a,@a+dptr ; )
mov r0,a ; )
mov a,r4 ; )
rl a ; )
inc a ; )
movc a,@a+dptr ; )
mov dph,r0 ; /
acall X405f ; Jump to function looked up.
sjmp X403a ; Jump to start of waiting loop.
;
X405f: jmp @a+dptr ; Jump to function looked up.
;
; Send value of port 1 and toggle p1.7.
; (Called from fptr table at 0x4000.)
X4060: mov a,p1 ; a=p1
cpl p1.7 ; p1.7 = ~p1.7
ret
;
; Set [0x88].
; (Called from fptr table at 0x4000.)
X4065: acall X43ae ; Check if key checked and receive byte.
setb p1.0 ; Set p1.0
X4069: mov 94h,#40h ; [0x94] = 0x40
mov 088h,a ; [0x88] = a
ret
;
; Verify again mask key and set [0xBD], [0xD8] or [0xFD].
; (Called from fptr table at 0x4000.)
X406f: acall X4085 ; Verify mask key for a second time.
acall X43ae ; Check if key checked and receive byte.
mov r3,a ; r3 = a
acall X43ae ; Check if key checked and receive byte.
jz X407e ; if( byte2==0 ) goto X407e
dec a ; a--
jz X4081 ; if( byte2==1 ) goto X4081
mov 0fdh,r3 ; [0xFD] = byte1
ret
; For byte2==0
X407e: mov eetime,r3 ; [0xBD] = byte1
ret
; For byte2==1
X4081: mov a,r3 ; a = byte1
X4082: ljmp X02b9 ; Do magic with [0xD8].
; Verify again mask key.
X4085: push dph ; \
push dpl ; / Save dptr
mov dptr,#X43f8 ; dptr = 0x43f8 (address of mask key)
mov r3,#8
clr c ; Clear c
X408f: push psw ; Save psw
acall X43ae ; Check if key checked and receive byte.
mov r0,a ; r0 = a
pop psw ; Restore psw
clr a ; a = 0
movc a,@a+dptr ; a = [dptr]
xrl a,r0 ; a ^= r0
addc a,#0ffh ; a += 0xFF + c
inc dptr ; dptr++
djnz r3,X408f ; Loop 8 times
X409e: jc X409e ; Loop forever if( c i.e. key did not match )
pop dpl ; \
pop dph ; / Restore dptr
clr a ; a = 0
ret
;
; (Called from fptr table at 0x4000.)
X40a6: acall X40cd
acall X40ec ; NOP? It just does the last instructions again
mov r3,a ; r3 = 0 \
mov r4,a ; r4 = 0 ) Counter
mov r5,a ; r5 = 0 /
X40ad: movx a,@dptr ; a = [dptr] (= [0x80??])
; Count bits differing between byte2 and [dptr]
xrl a,r6 ; a ^= byte2
jz X40c1 ; if( byte2==[dptr] ) goto X40c1
mov r7,#8
X40b3: rrc a ; Rotate right a into c
jnc X40bf ; if( !c ) goto X40bf
inc r5 ; r5++
cjne r5,#0,X40bf ; if( r5 ) goto X40bf
inc r4 ; r4++
cjne r4,#0,X40bf ; if( r4 ) goto X40bf
inc r3 ; r3++
X40bf: djnz r7,X40b3 ; Loop 8 times
X40c1: inc dptr ; dptr++
djnz r1,X40ad ; Loop 0xE0/0xC0 times
djnz r2,X40ad ; Loop [0xFA] times
lcall X02ca ; Do magic with [0xD8].
mov r2,#3 ; r2 = 3
ajmp X415d
;
X40cd: acall X43ae ; Check if key checked and receive byte.
mov r5,a ; r5 = byte1
acall X43ae ; Check if key checked and receive byte.
mov r6,a ; r6 = byte2
X40d3: mov dptr,#X8000 ; dptr = 0x8000
movx a,@dptr ; a = [0x8000]
mov r2,a ; r2 = [0x8000]
mov a,r6 ; a = byte2
xch a,r5 ; swap a, r5
acall X4082 ; Do magic with [0xD8].
mov a,r2 ; a = [0x8000]
mov r1,#0e0h ; r1 = 0xe0
mov r2,0fah ; r2 = [0xFA]
xrl a,#0a9h ; a ^= 0xA9
jnz X40f2 ; if( [0x8000]!= 0xA9 ) return
cjne r2,#40h,X40e8 ; \
X40e8: jc X40ec ; / if( [0xFA]<0x40 ) goto X40ec
mov r1,#0c0h ; r1 = 0xC0
X40ec: mov a,r1 ; a = r1
dec a ; a--
cpl a ; a = ~a
mov dpl,a ; dpl = a
clr a ; a = 0
X40f2: ret
;
; (Called from fptr table at 0x4000.)
X40f3: lcall X02b7 ; Read byte and do magic with [0xD8].
acall X43ae ; Check if key checked and receive byte.
mov r6,a ; r6 = byte1
acall X43ae ; Check if key checked and receive byte.
mov r5,a ; r5 = byte2
jz X40ff ; if( byte1==0 ) goto X40ff
inc r6 ; byte1++
X40ff: acall X43ae ; Check if key checked and receive byte.
lcall X00c7
X4104: lcall X0258
djnz r5,X4104 ; if( r5 ) goto X4104
djnz r6,X4104 ; if( r6 ) goto X4104
ret
;
; Set PSW and return 0x72.
; (Called from fptr table at 0x4000.)
X410c: acall X43ae ; Check if key checked and receive byte.
mov psw,a ; psw = byte1
mov a,#72h ; a = 0x72
ret
;
; (Called also from fptr table at 0x4000.)
X4113: clr c ; Clear c
mov r7,0fah ; r7 = [0xFA]
mov dptr,#X8010 ; dptr = 0x8010
sjmp X4126
;
; (Called also from fptr table at 0x4000.)
X411b: clr c ; Clear c
mov r7,pwena ; r7 = [0xFE]
sjmp X4123
;
; (Called from fptr table at 0x4000.)
X4120: setb c ; Set c
mov r7,#0ah ; r7 = 0x0A
X4123: mov dptr,#X0000 ; dptr = 0x0000
X4126: clr a ; a = 0
mov r0,a ; r0 = 0
mov r3,a ; r3 = 0 \
mov r4,a ; r4 = 0 / Counter
mov r5,a ; r5 = 0
mov r6,#5ah ; r6 = 0x5A
mov b,r6 ; b = 0x5A
jnc X414c ; if( !c ) jump to 414c
X4131: mov a,#0ffh ; a = 0xFF
db 0a5h ; Reserved instruction
nop
xch a,r6 ; \
xrl a,r6 ; ) r6 = (r6 ^ a) >>> 1
rr a ; )
xch a,r6 ; /
add a,r5 ; a += r5
mov r5,a ; r5 = a
jnc X4142 ; if( (a+r5)<=0xFF ) goto X4142
inc r4 ; r4++
mov a,r4 ; a = r4
jnz X4142 ; if( r4!=0 ) goto X4142
X4141: inc r3 ; r3++
X4142: inc dptr ; dptr++
djnz r0,X4131 ; Loop r0 (=0?) times
djnz r7,X4131 ; Loop 10 times
sjmp X415b
;
X4149: clr a ; a = 0
mov dpl,a ; dpl = 0
X414c: db 0a5h ; Reserved instruction
nop
add a,r5 ; \
mov r5,a ; / r5 += a
mov a,dpl ; \
addc a,r4 ; ) r4 += dpl + c
mov r4,a ; /
jnc X4157 ; if( !c ) goto X4157
inc r3 ; r3++
X4157: djnz r7,X4149 ; Loop 10 times
mov r6,b ; r6 = b
X415b: mov r2,#4 ; r2 = 4
X415d: mov r1,#3 ; r1 = 3
X415f: mov a,@r1 ; a = [r1]
cjne r2,#1,X4164 ; if( r2!=1 ) goto X4164
ret
;
X4164: acall X437d ; Send byte (0x437d).
inc r1 ; r1++
djnz r2,X415f ; Loop r2 times
;
; (Called from fptr table at 0x4000.)
X4169: mov dptr,#X0000 ; dptr = 0x0000
acall X43ae ; Check if key checked and receive byte.
orl dph,a ; dph = byte
mov r6,#0 ; r6 = 0
X4172: mov a,#0ffh ; a = 0xFF
db 0a5h ; Reserved instruction
nop
cjne r6,#1,X417a ; if( r6!=1 ) goto X417a
ret
X417a: inc dptr ; dptr++
acall X437d ; Send byte (0x437d).
djnz r6,X4172 ; Loop 256-1 times
;
; Test internal RAM?
; (Called from fptr table at 0x4000.)
X417f: mov dph,rb1r0 ; dph = 0x43 (from dph)
setb c ; Set c
X4183: mov r0,#0ffh ; r0 = 0xFF
X4185: mov a,r0 ; a = r0
jc X4189 ; \ if( !c ) a = ~a
cpl a ; /
X4189: mov @r0,a ; [r0] = a
djnz r0,X4185 ; Loop 255 times
dec r0 ; r0 = 0xFF
X418d: mov a,@r0 ; a = [r0]
jc X4191 ; \ if( !c ) a = ~a
cpl a ; /
X4191: xrl a,r0 ; a ^= r0
jnz X41a9 ; if( r0!=(~)[r0] ) goto X41a9
djnz r0,X418d ; Loop 255 times
cpl c ; Toggle c
jnc X4183 ; if( !c ) goto X4183 (repeat again without ~)
X4199: cpl a ; a = ~a
mov dpl,a ; dpl = a
dec r0 ; r0--
X419d: mov @r0,a ; [r0]=a
djnz r0,X419d ; Loop r0 times
dec r0 ; r0--
X41a1: mov a,@r0 ; a = [r0]
cjne a,dpl,X41a9 ; if( a!=dpl ) goto X41a9
djnz r0,X41a1 ; Loop r0 times
jnz X4199 ; if( a!=0 ) goto X4199
X41a9: mov a,r0 ; a = r0
X41aa: mov sp,#7 ; [0x81] = 7
push dph ; Save dph to [0x07]?
ajmp X403a ; Command loop
;
; Write into RAM?
; (Called from fptr table at 0x4000.)
X41b1: acall X43ae ; Check if key checked and receive byte.
mov adrxh,a ; [0xB3] = byte1
mov b,a ; b = byte1 (Flags)
acall X43ae ; Check if key checked and receive byte.
mov r1,a ; r1 = byte2 (Start address)
acall X43ae ; Check if key checked and receive byte.
mov r4,a ; r4 = byte3 (Length)
acall X4085 ; Verify again mask key.
mov r3,a ; r3 = 0
mov dph,rb1r0 ; dph = 0x43 (from dph)
X41c3: acall X43ae ; Check if key checked and receive byte.
jnb b.7,X41de ; if( !b.7 ) goto X41de
cjne r1,#5,X41cb ; \
X41cb: jc X41d8 ; / if( ri<5 ) goto X41d8
; internal RAM
mov @r1,a ; [r1] = a
xrl a,@r1 ; a ^= [r1]
X41cf: jb b.6,X41d8 ; if( b.6 ) goto X41d8
jz X41d8 ; if( a!=0 (write error?) ) goto X41d8
mov a,r1 ; a = r1
mov r3,a ; r3 = r1
setb b.6 ; Set b.6
X41d8: inc r1 ; r1++
djnz r4,X41c3 ; Loop r4 times
mov a,r3 ; a = r3
ajmp X41aa ; Fiddle with stack an return to command loop
; external RAM/EEPROM
X41de: movx @r1,a ; ext[r1] = a
mov r5,a ; r5 = a
movx a,@r1 ; a = ext[r1]
xrl a,r5 ; a ^= r5
sjmp X41cf
;
; Send byte2-1 bytes starting at address byte1 from internal RAM.
; (Called from fptr table at 0x4000.)
X41e4: acall X43ae ; Check if key checked and receive byte.
mov r1,a ; r1 = byte1 (Address)
acall X43ae ; Check if key checked and receive byte.
mov r4,a ; r4 = byte2 (Length+1)
acall X4085 ; Verify again mask key.
mov a,r4 ; a = r4
mov r2,a ; r2 = r4
ajmp X415f
;
; Read starting at dptr byte1-1 bytes from ROM or EEPROM.
; (Called from fptr table at 0x4000.)
X41f0: lcall X02ae ; Read dptr from IO.
acall X43ae ; Check if key checked and receive byte.
mov r5,a ; r5 = byte1 (Length+1)
acall X4085 ; Verify again mask key.
X41f8: cjne r4,#17h,X4200 ; if( r4!=0x17 (function number) ) goto X4200
mov a,dph ; a = dph
jnb acc.7,X4203 ; if( !acc.7(in EEPROM) ) goto X4203
X4200: movx a,@dptr ; a = ext[dptr]
sjmp X4210 ; goto X4210
X4203: clr a ; a = 0
movc a,@a+dptr ; a = rom[dptr]
mov r1,a ; r1 = a
mov adrxh,#80h ; [0xB3]=0x80
mov r0,#0 ; r0 = 0
movx a,@r0 ; a = [r0]
X420c: cjne a,#0a9h,X420c ; Loop forever if( a!=0xa9 )
mov a,r1 ; a = r1
X4210: cjne r5,#1,X4214 ; if( r5!=1 ) goto X4214
X4213: ret
;
X4214: acall X437d ; Send byte (0x437d).
inc dptr ; dptr++
djnz r5,X41f8 ; Loop r5-1 times
;
; Jump to function pointed to by dptr.
; (Called from fptr table at 0x4000.)
X4219: lcall X02ae ; Read dptr from IO.
acall X4085 ; Verify again mask key.
jmp @a+dptr ; goto [dptr]
;
; (Called from fptr table at 0x4000.)
X421f: acall X40cd
acall X4225 ; Compare somehow bytes in EEPROM
ajmp X42a1 ; if( a!=0 ) send a and fiddle with [0xD8]
;
; Compare somehow bytes in EEPROM
X4225: mov r4,a ; r4=a (=0?)
jz X4239 ; if( a==0 ) goto X4239
mov r4,#20h ; r4=0x20
X422a: movx a,@dptr ; a = ext[0x80??]
xrl a,r5 ; a ^= byte1 (Compare byte1 with ext[0x80??])
jnz X4242 ; if( a!=0 ) ret
inc dptr ; dptr++
dec r4 ; r4--
cjne r4,#10h,X4236 ; if( r4!=0x10 ) goto X4236
xrl rb0r5,#0ffh ; r5@rb0 ^= 0xFF
X4236: cjne r4,#0,X422a ; if( r4!=0 ) goto X422a (loop)
X4239: movx a,@dptr ; a = ext[0x80??]
xrl a,r6 ; a ^= byte2 (Compare byte2 with ext[0x80??])
jnz X4242 ; if( a!=0 ) ret
inc dptr ; dptr++
djnz r1,X4239 ; Loop r1 times
djnz r2,X4239 ; Loop r2 times
X4242: ret
;
X4243: mov a,#81h ; a = 0x81
X4245: mov r5,a ; r5 = a
mov r6,#0ffh ; r6 = 0xFF
sjmp X4252 ; goto X4252
X424a: mov r5,#80h ; r5 = 0x80
mov r6,#0 ; r6 = 0x00
sjmp X4252 ; goto X4252
X4250: mov r5,#0 ; r5 = 0
X4252: acall X40d3
acall X4225 ; Compare somehow bytes in EEPROM
X4256: ljmp X02ca ; Do magic with [0xD8].
;
; (Called from fptr table at 0x4000.)
X4259: mov 0fdh,#0ach ; [0xFD] = 0xAC
acall X42fa
mov 0fdh,#0c9h ; [0xFD] = 0xC9
acall X424a
jz X426f ; if( a==0 ) goto X426f
mov 0fdh,#0d9h ; [0xFD] = 0xD9
acall X4236 ; Compare somehow EEPROM
jz X426f ; if( a==0 ) goto X426f
mov 0fdh,#0e9h ; [0xFD] = 0xE9
X426f: mov a,#0d0h ; a = 0xD0
acall X42e9
inc 0fdh ; [0xFD]++
clr a ; a = 0
acall X4245
jz X4286 ; if( a==0 ) goto X4286
inc 0fdh ; [0xFD]++
mov a,#80h ; a = 0x80
acall X4082 ; Do magic with [0xD8].
acall X4236 ; Compare somehow EEPROM
jz X4286 ; if( a==0 ) goto X4286
inc 0fdh ; [0xFD]++
X4286: mov dph,#55h ; dph = 0x55
mov dpl,0fdh ; dpl = [0xFD]
ajmp X42a6 ; Send dph and do magic with [0xD8].
;
; (Called from fptr table at 0x4000.)
X428e: acall X42f4
mov 2fh,#0b4h ; [0x2F] = 0xB4
clr a ; a = 0
acall X42e9
acall X424a
jnz X42a6 ; if( a!=0 ) goto X42a6
mov dptr,#X8081 ; dptr = 0x8081
acall X42ee
acall X424a
X42a1: jnz X42a6 ; if( a!=0 ) goto X42a6
mov dptr,#X5555 ; dptr = 0x5555
X42a6: mov a,dph ; a = dph
acall X437d ; Send byte (0x437d).
mov a,dpl ; a = dpl
ajmp X4256 ; Do magic with [0xD8].
;
; (Called from fptr table at 0x4000.)
X42ae: acall X43ae ; Check if key checked and receive byte.
push 0fdh ; Save [0xFD]
mov 2fh,a ; [0x2F] = a (bit area)
anl 2fh,#0f0h ; [0x2F] &= 0xF0
mov r0,#0f0h ; r0 = 0xF0
jb 2fh.6,X42bf ; if( [0x2F].6 ) goto 0x42bf
mov r0,#0fh ; r0 = 0x0F
swap a ; swap nibbles of a
X42bf: orl a,r0 ; a |= r0 (0xF0 or 0x0F)
mov c,2fh.7 ; c = [0x2F].7
jc X42c8 ; if( [0x2F].7 ) goto X42c8
xrl a,r0 ; a ^= r0 (0xF0 or 0x0F)
xch a,0fdh ; swap a and [0xFD]
anl a,r0 ; a &= r0 (0xF0 or 0x0F)
X42c8: addc a,0fdh ; a += [0xFD] + [0x2F].7
mov 0fdh,a ; [0xFD] = a
setb 2fh.7 ; Set [0x2F].7
clr a ; a = 0
acall X42f6
pop 0fdh ; Restore [0xFD]
jb 2fh.6,X42d7 ; if( [0x2F].6 ) goto 0x42D7
dec r6 ; r6++
X42d7: acall X4250
ajmp X42a1
;
; (Called from fptr table at 0x4000.)
X42db: acall X42f4
acall X424a
jnz X42a6 ; if( a ) goto X42a6
acall X42e7
acall X4243
ajmp X42a1 ; goto X42a1
;
X42e7: mov a,#30h ; a = 0x30
X42e9: mov dptr,#X8080 ; dptr = 0x8080
acall X4082 ; Do magic with [0xD8].
X42ee: mov r1,#30h ; r1 = 0x30
X42f0: mov a,r6 ; a = r6
ljmp X024f
;
X42f4: mov a,#50h ; a = 0x50
X42f6: mov r6,#0 ; r6 = 0
sjmp X42e9 ; Goto X42e9
;
X42fa: mov r6,#0 ; r6 = 0
mov a,#0b0h ; a = 0xB0
sjmp X42e9 ; Goto X42e9
;
; (Called from fptr table at 0x4000.)
X4300: acall X40cd
mov r7,eepage ; r7 = [0xFB]
mov a,#80h ; a = 0x80
mov b,r7 ; b = [0xFB]
div ab ; a=a/b; b=a mod b
rl a ; a = a<<<1
mov r5,a ; r5 = a
mov r1,a ; r1 = a
X430c: movx a,@dptr ; a = [dptr] (=[0x80??])
xrl a,r6 ; \
jnz X4330 ; / if( a != r6(byte2) ) goto 0x4330
inc dptr ; dptr++
jb b.6,X4323 ; if( b.6 ) next
mov a,dpl ; a = dpl
cjne a,#20h,X431d ; if( dpl!=0x20 ) goto X431d
setb b.6 ; Set b.6
sjmp X4320 ; Goto X4320
X431d: cjne a,#10h,X4323 ; if( dpl!=0x10 ) next
X4320: xrl rb0r6,#0ffh ; r6@rb0 ^= 0xFF
X4323: djnz r7,X430c ; Loop r7 times
xrl rb0r6,#0ffh ; r6@rb0 ^= 0xFF
mov r7,eepage ; r7 = [0xFB]
djnz r1,X430c ; Loop r1 ( (0x80/[0xFB])<<<1 ) times
mov r1,rb0r5 ; r1 = r5@rb0
djnz r2,X430c ; Loop r2 ([0xFA]) times
X4330: ajmp X42a1 ; Goto X42a1
;
; (Called from fptr table at 0x4000.)
X4332: mov r7,#2 ; r7 = 2
setb b.0 ; Set b.0
mov r6,#0 ; r6 = 0
X4338: mov r5,0f9h ; r5 = [0xF9]
clr a ; a = 0
mov adrxh,a ; [0xB3] = 0
mov dptr,#X0000 ; dptr = 0x0000
mov r0,a ; r0 = 0
X4341: clr a ; a = 0
cjne r7,#2,X434c ; if( r7!=2 ) goto X434c
mov a,r0 ; a = r0
jb b.0,X434b ; if( b.0 ) goto X434b
cpl a ; a = ~a
inc a ; a++
X434b: add a,r5 ; a += r5
X434c: xrl a,r6 ; a ^= r6
jb b.0,X4358 ; if( b.0 ) goto X4358
mov r4,a ; \
movx a,@dptr ; ) a ^= [dptr] (=0x33?)
xrl a,r4 ; /
jnz X437b ; if( a ) goto X437b
inc dptr ; dptr++
sjmp X4359 ; goto X4359
X4358: movx @r0,a ; [r0] = a
X4359: djnz r0,X4341 ; Loop r0 times
inc adrxh ; [0xB3]++
djnz r5,X4341 ; Loop r5 times
cpl b.0 ; Toggle b.0
jnb b.0,X4338 ; if( !b.0 ) goto X4338
mov a,r6 ; a = r6
cpl a ; a = ~a
mov r6,a ; r6 = a
jnz X4338 ; if( a ) goto X4338
djnz r7,X4338 ; Loop r7 times
mov adrxh,#2 ; [0xB3] = 2
mov r7,#7 ; r7 = 7
clr c ; Clear c
X4371: movx @r0,a ; [r0] = a
xch a,adrxh ; \
rlc a ; ) rotate left [0xB3] into carry
xch a,adrxh ; /
djnz r7,X4371 ; Loop 7 times
movx a,@r0 ; a = [r0]
cpl a ; a = ~a
X437b: ajmp X42a1 ; Goto X42a1
;
; Send byte (0x437d).
X437d: anl 94h,#0feh ; Clear [0x94].0
X4380: jnb p1.0,X4380 ; Wait for p1.0 to become 1.
setb p1.0 ; Set p1.0
orl 94h,#1 ; Set [0x94].0
mov r0,#0ah
clr c
nop
jnb f0,X43a8 ; Transmit a without setting psw.1.
jnb psw.1,X439a ; Send byte with delay. (4.91MHz?)
; Transmit ca. 100000bps@3.57MHz
X4392: mov p1.0,c ; Write p1.0
rrc a ; Rotate right a into c
xch a,acc ; NOP ?
djnz r0,X4392 ; Loop 10 times
ret
;
; Send byte with delay.
X439a: acall X43d2 ; NOP
acall X43d1 ; NOP
X439e: mov p1.0,c
rrc a
acall X43d1 ; NOP
xch a,@r0 ; NOP ?
xch a,@r0 ; NOP ?
djnz r0,X439e ; Loop 10 times
ret
;
X43a8: lcall X036d ; Transmit a without setting psw.1.
ljmp X03a4 ; Wait dependant on psw.1
;
; Check if mask key has been checked and receive byte.
X43ae: mov a,rb1r0 ; a = 0x43 (from dph)
X43b0: cjne a,#43h,X43b0 ; Loop forever if a is not 0x43.
X43b3: anl 94h,#0feh ; Clear [0x94].0.
jb f0,X43bc ; If( f0 ) jump 0x43bc.
ljmp X033e ; Wait for byte and write it into a.
X43bc: jnb p1.0,X43bc ; Wait for p1.0 set
X43bf: jb p1.0,X43bf ; Wait for p1.0 cleared
mov r0,#9
X43c4: mov c,p1.0 ; Read p1.0.
rrc a ; Rotate right c into a
jnb psw.1,X43d4 ; if( !psw.1 ) do some delay.
X43ca: djnz r0,X43c4 ; Loop 9 times
orl 94h,#1 ; Set [0x94].0.
clr p1.0 ; Clear p1.0.
X43d1: nop
X43d2: nop
X43d3: ret
X43d4: acall X43d3
ajmp X43ca
;
X43d8: 00 00 00 00 00 00 00 00
X43e0: 00 00 00 00 00 00 00 00
X43e8: 00 00 00 00 00 00 00 00
X43f0: 00 00 00 00 00 00 00 72
X43f8: 21 c0 35 08 81 db d5 08
end