public static Ram GetLayoutAnnotated() { var ram = new Ram(); // I think this is map layout (when to read a block of sea or something or when to read map data) // see debug log: trying to find water 02 // code start: c04923 // code end: c04a43 // code never hits: c049b3 (does hit when loading cave map) // $ed8a00 - $ed9be2 var layoutSource = Rom.ByteArray(0xed8a00); var output = ram.WordArray(0x7f0000); var outputf3c6 = ram.ByteArray(0x7ff3c6); //c04923 php //c04924 %setAXYto16bit() //c04926 pha //c04927 phx //c04928 phy //c04929 sta $1c //c0492b stx $20 //c0492d stz $18 //c0492f stz $1a //c04931 lda #$03be //c04934 sta $1e //c04936 stz $22 //c04938 ldx #$0000 //c0493b stz $f3c6,x //c0493e inx //c0493f inx //c04940 cpx #$0400 //c04943 bcc $493b //c04945 ldy #$0000 //c04948 tya //c04949 %setAto8bit() // c04929 ushort x18x19 = 0; int x1c = 0x1000; // comes from outside (A) int x1e = 0x03BE; byte x1a = 0; byte x1b = 0; int x20 = 0; // comes from outside (X) byte x22 = 0; // don't have initial values? byte x24 = 0; byte x25 = 0; // $c04945 var y = 0; // A => 8bit // .Branch_c0494b -- top while (true) { //c0494b lsr $19 //c0494d ror $18 x18x19 = (ushort)(x18x19 >> 1); //c0494f lda $19 //c04951 lsr //c04952 bcs .Branch_c0495b if ((x18x19 & 0x0100) == 0) { //c04954 lda [$00],y //c04956 iny //c04957 sta $18 //c04959 dec $19 x18x19 = (ushort)((x18x19 - 0x0100 & 0xff00) + layoutSource[y]); y++; } //.Branch_c0495b //c0495b lda $18 //c0495d lsr //c0495e bcc .Branch_c049b4 if ((x18x19 & 0x0001) != 0) { //c04960 lda $22 //c04962 lsr //c04963 bcs .Branch_c0497e if ((x22 & 0x01) == 0) { //c04965 lda [$00],y //c04967 iny //c04968 sta $24 //c0496a ldx $1e //c0496c sta $f3c6,x x24 = layoutSource[y]; outputf3c6[x1e] = layoutSource[y]; y++; //c0496f inc $1e //c04971 bne .Branch_c0497a //c04973 lda $1f //c04975 inc //c04976 and #$03 //c04978 sta $1f //.Branch_c0497a x1e++; x1e &= 0x03ff; //c0497a inc $22 x22++; //c0497c bra .Branch_c0494b // back to top continue; } //.Branch_c0497e //c0497e lda [$00],y //c04980 iny //c04981 sta $25 //c04983 ldx $1e //c04985 sta $f3c6,x x25 = layoutSource[y]; outputf3c6[x1e] = layoutSource[y]; y++; //c04988 inc $1e //c0498a bne .Branch_c04993 //c0498c lda $1f //c0498e inc //c0498f and #$03 //c04991 sta $1f //.Branch_c04993 //c04993 inc $22 x1e++; x1e &= 0x03ff; x22++; //c04995 rep #$20 // ---------------------------------A => 16bit //c04997 ldx $20 //c04999 lda $24 //c0499b sta $0000,x //c0499e inx //c0499f inx //c049a0 stx $20 output[x20] = (ushort)(x24 + (x25 << 8)); x20 += 2; //c049a2 dec $1c x1c--; //c049a4 beq .Branch_c049ad if (x1c != 0) { //c049a6 lda #$0000 //c049a9 sep #$20 // ---------------------------------A => 8bit //c049ab bra .Branch_c0494b // back to top continue; } else { //.Branch_c049ad //c049ad %setAXYto16bit() //c049af ply //c049b0 plx //c049b1 pla //c049b2 plp //c049b3 rtl return(ram); // EXIT } } //.Branch_c049b4 // carry will be clear //c049b4 lda [$00],y //c049b6 iny //c049b7 sta $1a x1a = layoutSource[y]; y++; //c049b9 lda [$00],y //c049bb rol //c049bc rol //c049bd rol //c049be and #$03 //c049c0 sta $1b x1b = (byte)(layoutSource[y] >> 6 & 0x03); //c049c2 lda [$00],y //c049c4 iny //c049c5 and #$3f //c049c7 clc //c049c8 adc #$03 //c049ca phy //c049cb tay byte counter = (byte)((layoutSource[y] & 0x3f) + 3); y++; //.Branch_c049cc while (true) { //c049cc dey counter--; //c049cd bmi .Branch_c04a3a if (SNES.IsNegative16(counter)) { break; } //c049cf lda $22 //c049d1 lsr //c049d2 bcs .Branch_c049fc if ((x22 & 0x01) == 0) { //c049d4 ldx $1a //c049d6 lda $f3c6,x //c049d9 sta $24 //c049db inc $1a x24 = outputf3c6[x1a]; // TODO: Wrong, needs to be 16bit x1a x1a++; //c049dd bne .Branch_c049e8 if (x1a == 0) { //c049df lda $1b //c049e1 inc //c049e2 and #$03 //c049e4 sta $1b x1b++; x1b &= 0x03; //c049e6 lda $24 } //.Branch_c049e8 //c049e8 ldx $1e //c049ea sta $f3c6,x outputf3c6[x1e] = x24; //c049ed inc $1e //c049ef bne .Branch_c049f8 //c049f1 lda $1f //c049f3 inc //c049f4 and #$03 //c049f6 sta $1f //.Branch_c049f8 x1e++; x1e &= 0x03ff; //c049f8 inc $22 x22++; //c049fa bra .Branch_c049cc } else { //.Branch_c049fc //c049fc ldx $1a //c049fe lda $f3c6,x //c04a01 sta $25 x25 = outputf3c6[x1a]; // TODO: Wrong, needs to be 16bit x1a //c04a03 inc $1a x1a++; //c04a05 bne .Branch_c04a10 if (x1a == 0) { //c04a07 lda $1b //c04a09 inc //c04a0a and #$03 //c04a0c sta $1b x1b++; x1b &= 0x03; //c04a0e lda $25 } //.Branch_c04a10 //c04a10 ldx $1e //c04a12 sta $f3c6,x outputf3c6[x1e] = x25; //c04a15 inc $1e //c04a17 bne .Branch_c04a20 //c04a19 lda $1f //c04a1b inc //c04a1c and #$03 //c04a1e sta $1f //.Branch_c04a20 x1e++; x1e &= 0x03ff; //c04a20 inc $22 x22++; //c04a22 rep #$20 //---------------------------------- A=> 16bit //c04a24 ldx $20 //c04a26 lda $24 //c04a28 sta $0000,x //c04a2b inx //c04a2c inx //c04a2d stx $20 output[x20] = (ushort)(x24 + (x25 << 8)); x20 += 2; //c04a2f dec $1c x1c--; //c04a31 beq .Branch_c04a3e if (x1c == 0) { return(ram); // EXIT } //c04a33 lda #$0000 //c04a36 sep #$20 // ---------------------------------A => 8bit //c04a38 bra .Branch_c049cc } } //.Branch_c04a3a //c04a3a ply //c04a3b jmp Jump_c0494b // back to top } // end of while //.Branch_c04a3e -- EXIT //c04a3e ply //c04a3f ply //c04a40 plx //c04a41 pla //c04a42 plp //c04a43 rtl }
/* * Work area is ring buffer of $400 bytes, starts as zeros, destination starts at $3be * Reads from source data in order, writes to output and ring buffer in order * Command byte is 8 command bits: * 1 => read one byte (and write to output and ring buffer) * 0 => read two bytes * 10 bits are start address in ring buffer * 6 bits are number of bytes to copy (plus 3, so counter can be 3 to 66) * copy bytes from ring buffer starting at source address, * while writing to ring buffer destination address and output at same time) * So each command byte is followed by 8 to 16 bytes of data * */ // Output is ram $7f0000 - $7f1fff ($2000 bytes) // A => exitCounter // X => destinationAddress public static RamWordArray GetLayout() { // TODO: this can be greater simplified and won't require Ram class usage //(int A, int X) { // I think this is map layout (when to read a block of sea or something or when to read map data) // see debug log: trying to find water 02 // code start: c04923 // code end: c04a43 // code never hits: c049b3 (does hit when loading cave map) // $ed8a00 - $ed9be2 var ram = new Ram(); var layoutSource = Rom.ByteArray(0xed8a00); var output = ram.WordArray(0x7f0000); var work = ram.ByteArray(0x7ff3c6); /* * Output at $7f0000 should be $2000 bytes * Each word represents 4 columns by 4 rows of tilemap data --- this might not be right * So 256 x 256 is reduced to pointers for 64 x 64 * This allows for easy repeat/reuse of blocks of sea etc. */ // $18-$19, initialized to 0 // TODO: should resplit these // $19 is $00 (-1 so $ff, read $18 from source) // $ff, $7f, $3f, $1f, $0f, $07, $03, $01, $00 = restart // basically a counter to 8 // regex @"ROR \$18 \[000018\] = \$.{62}C" shows all but first >> puts a 1 in $18 high bit (carry set because bit from $19 is 1) ushort command = 0; // $1c -- 16bit -- comes from outside (A) // each decrement is 2 bytes of output, so $2000 bytes // TODO: could be replaced with destination address offset? might be more than one setup (dest might not be zero in caves or something) int exitCounter = 0x1000; // $1e -- 16bit // masked with 0x03ff so $400 bytes of ring memory int workDestination = 0x03be; // $1a -- 16bit // masked with 0x03ff so $400 bytes of ring memory int workSource; // $20 -- 16bit -- comes from outside (X) // $0000 to $1ffe by +=2 ($2000 bytes) int destinationAddress = 0; // $22 -- 8bit // overflows from $ff to $00 // is really just high byte/low byte indicator byte columnIndex = 0; // don't need initial values // don't need to be differentiated, could just write byte by byte // $24 byte lowValue = 0; // $25 byte highValue = 0; // Y -- 16bit var sourceAddress = 0; while (true) { // decrement $19 basically, and rotate a one into the high bit of $18 (except first time in which $18 is thrown out anyways) command = (ushort)(command >> 1); // is $19 zero (happens at beginning of every cycle of 8) // Gets new command byte $18 (each bit says how next bytes are interpreted) if ((command & 0x0100) == 0) { //set $19 to $ff and read $18 from source command = (ushort)((command - 0x0100 & 0xff00) + layoutSource[sourceAddress]); sourceAddress++; } // is $18 odd (bit 0 == 1) --- command bit is 1 if ((command & 0x0001) != 0) { // loads one byte directly if ((columnIndex & 0x01) == 0) { // load low byte direct lowValue = layoutSource[sourceAddress]; work[workDestination] = layoutSource[sourceAddress]; sourceAddress++; workDestination++; workDestination &= 0x03ff; columnIndex++; } else { // load high byte direct and write output highValue = layoutSource[sourceAddress]; work[workDestination] = layoutSource[sourceAddress]; sourceAddress++; workDestination++; workDestination &= 0x03ff; columnIndex++; output[destinationAddress] = (ushort)(lowValue + (highValue << 8)); destinationAddress += 2; exitCounter--; if (exitCounter == 0) { return(output); // EXIT } } } else { // is $18 even (bit 0 == 0) --- command bit is 0 // copy part of work into output // next two source bytes are source address and number of bytes to copy // destination work buffer continues to fill // 10 bit number: low byte = ls[sa], high byte lower 2 bits = ls[sa+1] highest 2 bits // source address is absolute in buffer, not relative workSource = layoutSource[sourceAddress] + (layoutSource[sourceAddress + 1] << 2 & 0x0300); // counter is lower 6 bits + 3 // smallest value is (0 + 3) copy 3 bytes int counter = (layoutSource[sourceAddress + 1] & 0x3f) + 3; sourceAddress += 2; while (counter > 0) { counter--; if ((columnIndex & 0x01) == 0) { // copy low byte from work buffer lowValue = work[workSource]; work[workDestination] = lowValue; workSource++; workSource &= 0x03ff; workDestination++; workDestination &= 0x03ff; columnIndex++; } else { // copy high byte from work buffer and write to output highValue = work[workSource]; work[workDestination] = highValue; workSource++; workSource &= 0x03ff; workDestination++; workDestination &= 0x03ff; columnIndex++; var val = (ushort)(lowValue + (highValue << 8)); output[destinationAddress] = val; destinationAddress += 2; exitCounter--; if (exitCounter == 0) { return(output); // EXIT } } } } } }