231 lines
5.5 KiB
Plaintext
231 lines
5.5 KiB
Plaintext
map:
|
|
|
|
RAM:0x01~0x0f Seed 1 (own key seed)?
|
|
RAM:0x10 send/receive buffer?
|
|
RAM:0x11 Stream ID received from LOCK
|
|
RAM:0x12~0x1f Seed 2 (Stream ID part of lock seed)?
|
|
|
|
main:
|
|
goto initstream;
|
|
|
|
mainloop:
|
|
a=0x1;
|
|
mainloop2:
|
|
x=a;
|
|
for(x=a; x<16; x++) {
|
|
main_inner1:
|
|
bm=0x0;
|
|
call 34b(0x00+x) // prepare next stream bit (send)
|
|
bm=0x1;
|
|
call 34b(0x10+x) // prepare next stream bit (recv)
|
|
call 131 // bm=1; bl=0; a=P0
|
|
a=P0;
|
|
if(P0.0) die; // WTF? P0.0 is an output!
|
|
if(P0.1) die;
|
|
|
|
a=0x0;
|
|
a<->RAM[0x10]; // load A with next output stream bit (nibble)
|
|
P0=a; // LSB -> Key output
|
|
nop; // wait
|
|
a=P0; // read from lock
|
|
P0=0; // clear output port
|
|
RAM[0x10]=a; // store next input stream bit in RAM
|
|
bl=3; a=P3 // P3.0, which is usually UNCONNECTED,
|
|
// somehow determines how to deal with
|
|
// the input stream. This is SNES CIC specific.
|
|
// NOTE: For commonly used key operation / pin mapping we must assume
|
|
// that P3.0 is HIGH (1). (otherwise the key would die immediately)
|
|
bl=0
|
|
if(P3.0){
|
|
if(RAM[0x10].1) { // input stream bit set?
|
|
call 159 // bm=0; bl=0; a=P0 // switch "bank"
|
|
if(RAM[0x00].0) { // matches calculated bit?
|
|
goto 13d // then go on
|
|
} else goto 157 // DIE // else gtfo
|
|
} else goto input_stream_bit_clear // input stream bit clear, check
|
|
} else goto 175
|
|
|
|
input_stream_bit_clear: // input stream bit cleared
|
|
call 159 // bm=0; bl=0; a=P0 // switch "bank"
|
|
if(RAM[0x00].0) { // calculated bit doesn't match?
|
|
goto 157 // DIE // then die
|
|
} else goto 17a // nop; goto 13d // else go on
|
|
|
|
175:
|
|
if(RAM[0x10].0) { // this is essentially the same
|
|
call 159 // bm=0; bl=0; a=P0 // as above but
|
|
if(RAM[0x00].1) { // input stream bit is set in
|
|
goto 13d; // RAM[0x10].0 instead of .1 and
|
|
} else goto 157 // DIE // calculated from RAM[0x00].1
|
|
} else { // instead of .0, if P3.0 is 0.
|
|
call 159 // bm=0; bl=0; a=P0
|
|
if(RAM[0x00].1) {
|
|
goto 157 // DIE
|
|
} else goto 17a // nop; goto 13d
|
|
}
|
|
|
|
13d: // continue
|
|
a=x;
|
|
a++; // loop to next of 15 stream
|
|
if(!overflow) { // bits, afterwards:
|
|
x=a;
|
|
goto main_inner1;
|
|
}
|
|
} // for x=1 to 15
|
|
(x=0) //
|
|
call 04a // set Resets (dummy for key mode) // output reset levels
|
|
call 370 // "MANGLE BOTH" // calculate new seeds
|
|
call 370 // "MANGLE BOTH" // for both sides
|
|
call 370 // "MANGLE BOTH" // (lock+key) to exchange
|
|
// this is "SNES security": MANGLE is called THREE TIMES!
|
|
// as opposed to only once on the NES CICs.
|
|
a=RAM[0x13];
|
|
RAM[0x13]=RAM[0x17];
|
|
// set P3.0 to LSB of RAM[0x13]
|
|
P3 = (P3 & 0xe) | (RAM[0x13] & 0x1);
|
|
if(a.0==1) {
|
|
goto mainloop (seed offset=0x1)
|
|
} else goto mainloop2 (seed offset=a)
|
|
|
|
|
|
04a: // "RUN HOST"
|
|
call 37a // "skip if lock"
|
|
a=0x0;
|
|
P1=a;
|
|
nop
|
|
nop
|
|
nop
|
|
P1=a;
|
|
return
|
|
|
|
mangle_both:
|
|
call mangle(bm=0);
|
|
goto mangle(bm=1);
|
|
|
|
mangle:
|
|
bl=0xf;
|
|
a=RAM[bm:0xf];
|
|
x=a;
|
|
carry=1;
|
|
bl=0x1;
|
|
a+=RAM[bm:0x1]+1;
|
|
RAM[bm:0x1]=a;
|
|
==> RAM[bm:0x1]+=RAM[bm:0xf]+1;
|
|
a=RAM[bm:0x1]; bl++;
|
|
a+=RAM[bm:0x2]+1;
|
|
a=~a;
|
|
RAM[bm:0x2]=a; bl++;
|
|
a+=RAM[bm:0x3]+1;
|
|
if(!overflow) {
|
|
RAM[bm:0x3]=a; bl++;
|
|
}
|
|
a+=RAM[bm:0x4];
|
|
RAM[bm:0x4]=a;
|
|
a=RAM[bm:0x4]; bl++;
|
|
carry=0;
|
|
a+=RAM[bm:0x5]+0;
|
|
RAM[bm:0x5]=a; bl++;
|
|
a+=8;
|
|
a+=RAM[bm:0x6]+0;
|
|
RAM[bm:0x6]=a; bl++;
|
|
mangle_inner1:
|
|
a++;
|
|
nop
|
|
a+=RAM[bm:0x7..0xf]+0;
|
|
RAM[bm:0x7..0xf]=a;
|
|
a=RAM[bm:0x7..0xf]; bl++;
|
|
if(!overflow) goto mangle_inner1
|
|
a<->x;
|
|
a+=0xf;
|
|
if(!overflow) return;
|
|
goto mangle
|
|
|
|
131:
|
|
bm=0x0;
|
|
call 37a
|
|
(if(!lock)bm=1);
|
|
return;
|
|
|
|
37a:
|
|
|
|
34b: input x='bl'
|
|
// take a nibble out of the seed (indexed by bm:x)
|
|
// and set [bm:0], i.e. RAM[0x00] or RAM[0x10] like this:
|
|
// if(seednibble&1) {
|
|
// result=0b0000;
|
|
// } else {
|
|
// if(P3.0) {
|
|
// result=0b0101;
|
|
// } else {
|
|
// result=0b0010;
|
|
// }
|
|
// }
|
|
bl=x;
|
|
a=RAM[bm:x];
|
|
RAM[bm:0] = RAM[bm:x].0 ? 0x7 : 0x0;
|
|
|
|
a=P3; // WTF is P3????
|
|
bl=0;
|
|
if (P3.0==1) {
|
|
RAM[bm:0] &= 0b1101;
|
|
} else {
|
|
RAM[bm:0] &= 0b1010;
|
|
}
|
|
return
|
|
|
|
initstream:
|
|
if(P0.3==0) {
|
|
if(P0.3==0) {
|
|
A=RAM[0x11]; RAM[0x11]=0xf
|
|
input_stream_id_bit;
|
|
if !(A.1) RAM[0x11]&=0b0111
|
|
input_stream_id_bit;
|
|
if !(A.1) RAM[0x11]&=0b1110
|
|
input_stream_id_bit;
|
|
if !(A.1) RAM[0x11]&=0b1101
|
|
input_stream_id_bit;
|
|
if !(A.1) RAM[0x11]&=0b1011
|
|
nop
|
|
|
|
RAM[0x01]=0xb;
|
|
RAM[0x02]=0x1;
|
|
RAM[0x03]=0x4;
|
|
RAM[0x04]=0xf;
|
|
RAM[0x05]=0x4;
|
|
RAM[0x06]=0xb; // 0x6????
|
|
RAM[0x07]=0x5;
|
|
RAM[0x08]=0x7; // 0x8????
|
|
RAM[0x09]=0xf;
|
|
RAM[0x0a]=0xd; // 0xa????
|
|
RAM[0x0b]=0x6;
|
|
RAM[0x0c]=0x1; // 0xc????
|
|
RAM[0x0d]=0xe;
|
|
RAM[0x0e]=0x9;
|
|
RAM[0x0f]=0x8;
|
|
|
|
RAM[0x12]=0x9;
|
|
RAM[0x13]=0xa;
|
|
RAM[0x14]=0x1;
|
|
RAM[0x15]=0x8;
|
|
RAM[0x16]=0x5;
|
|
RAM[0x17]=0xf; // 0x7????
|
|
RAM[0x18]=0x1;
|
|
RAM[0x19]=0x1; // 0x9????
|
|
RAM[0x1a]=0xe;
|
|
RAM[0x1b]=0x1; // 0xb????
|
|
RAM[0x1c]=0x0;
|
|
RAM[0x1d]=0xd;
|
|
RAM[0x1e]=0xe;
|
|
RAM[0x1f]=0xc;
|
|
|
|
mainloop;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
input_stream_id_bit:
|
|
wait 6 cycles
|
|
A=P0
|
|
ret
|