====== 6510/8502 Undocumented Commands ====== -- A brief explanation about what may happen while using don't care states. ANE $8B A = (A | #$EE) & X & #byte same as A = ((A & #$11 & X) | ( #$EE & X)) & #byte In real 6510/8502 the internal parameter #$11 may occasionally be #$10, #$01 or even #$00. This occurs when the video chip starts DMA between the opcode fetch and the parameter fetch of the instruction. The value probably depends on the data that was left on the bus by the VIC-II. LXA $AB C=Lehti: A = X = ANE Alternate: A = X = (A & #byte) TXA and TAX have to be responsible for these. SHA $93,$9F Store (A & X & (ADDR_HI + 1)) SHX $9E Store (X & (ADDR_HI + 1)) SHY $9C Store (Y & (ADDR_HI + 1)) SHS $9B SHA and TXS, where X is replaced by (A & X). Note: The value to be stored is copied also to ADDR_HI if page boundary is crossed. SBX $CB Carry and Decimal flags are ignored but the Carry flag will be set in substraction. This is due to the CMP command, which is executed instead of the real SBC. ARR $6B This instruction first performs an AND between the accumulator and the immediate parameter, then it shifts the accumulator to the right. However, this is not the whole truth. See the description below. Many undocumented commands do not use AND between registers, the CPU just throws the bytes to a bus simultaneously and lets the open-collector drivers perform the AND. I.e. the command called 'SAX', which is in the STORE section (opcodes $A0...$BF), stores the result of (A & X) by this way. More fortunate is its opposite, 'LAX' which just loads a byte simultaneously into both A and X. $6B ARR This instruction seems to be a harmless combination of AND and ROR at first sight, but it turns out that it affects the V flag and also has a special kind of decimal mode. This is because the instruction has inherited some properties of the ADC instruction ($69) in addition to the ROR ($6A). In Binary mode (D flag clear), the instruction effectively does an AND between the accumulator and the immediate parameter, and then shifts the accumulator to the right, copying the C flag to the 8th bit. It sets the Negative and Zero flags just like the ROR would. The ADC code shows up in the Carry and oVerflow flags. The C flag will be copied from the bit 6 of the result (which doesn't seem too logical), and the V flag is the result of an Exclusive OR operation between the bit 6 and the bit 5 of the result. This makes sense, since the V flag will be normally set by an Exclusive OR, too. In Decimal mode (D flag set), the ARR instruction first performs the AND and ROR, just like in Binary mode. The N flag will be copied from the initial C flag, and the Z flag will be set according to the ROR result, as expected. The V flag will be set if the bit 6 of the accumulator changed its state between the AND and the ROR, cleared otherwise. Now comes the funny part. If the low nybble of the AND result, incremented by its lowmost bit, is greater than 5, the low nybble in the ROR result will be incremented by 6. The low nybble may overflow as a consequence of this BCD fixup, but the high nybble won't be adjusted. The high nybble will be BCD fixed in a similar way. If the high nybble of the AND result, incremented by its lowmost bit, is greater than 5, the high nybble in the ROR result will be incremented by 6, and the Carry flag will be set. Otherwise the C flag will be cleared. To help you understand this description, here is a C routine that illustrates the ARR operation in Decimal mode: unsigned A, /* Accumulator */ AL, /* low nybble of accumulator */ AH, /* high nybble of accumulator */ C, /* Carry flag */ Z, /* Zero flag */ V, /* oVerflow flag */ N, /* Negative flag */ t, /* temporary value */ s; /* value to be ARRed with Accumulator */ t = A & s; /* Perform the AND. */ AH = t >> 4; /* Separate the high */ AL = t & 15; /* and low nybbles. */ N = C; /* Set the N and */ Z = !(A = (t >> 1) | (C << 7)); /* Z flags traditionally */ V = (t ^ A) & 64; /* and V flag in a weird way. */ if (AL + (AL & 1) > 5) /* BCD "fixup" for low nybble. */ A = (A & 0xF0) | ((A + 6) & 0xF); if (C = AH + (AH & 1) > 5) /* Set the Carry flag. */ A = (A + 0x60) & 0xFF; /* BCD "fixup" for high nybble. */ $CB SBX X <- (A & X) - Immediate The 'SBX' ($CB) may seem to be very complex operation, even though it is a combination of the subtraction of accumulator and parameter, as in the 'CMP' instruction, and the command 'DEX'. As a result, both A and X are connected to ALU but only the subtraction takes place. Since the comparison logic was used, the result of subtraction should be normally ignored, but the 'DEX' now happily stores to X the value of (A & X) - Immediate. That is why this instruction does not have any decimal mode, and it does not affect the V flag. Also Carry flag will be ignored in the subtraction but set according to the result. Proof: begin 644 vsbx M`0@9$,D'GL(H-#,IJC(U-JS"*#0T*:HR-@```*D`H#V1*Z`_D2N@09$KJ0>% M^QBE^VEZJ+$KH#F1*ZD`2"BI`*(`RP`(:-B@.5$K*4#P`E@`H#VQ*SAI`)$K JD-Z@/[$K:0"1*Y#4J2X@TO\XH$&Q*VD`D2N0Q,;[$+188/_^]_:_OK>V ` end and begin 644 sbx M`0@9$,D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'BI`*!-D2N@3Y$KH%&1*ZD# MA?L8I?M*2)`#J1@LJ3B@29$K:$J0`ZGX+*G8R)$K&/BXJ?2B8\L)AOP(:(7] MV#B@3;$KH$\Q*Z!1\2L(1?SP`0!H1?TIM]#XH$VQ*SAI`)$KD,N@3[$K:0"1 9*Y#!J2X@TO\XH%&Q*VD`D2N0L<;[$))88-#X ` end These test programs show if your machine is compatible with ours regarding the opcode $CB. The first test, vsbx, proves that SBX does not affect the V flag. The latter one, sbx, proves the rest of our theory. The vsbx test tests 33554432 SBX combinations (16777216 different A, X and Immediate combinations, and two different V flag states), and the sbx test doubles that amount (16777216*4 D and C flag combinations). Both tests have run successfully on a C64 and a Vic20. They ought to run on C16, +4 and the PET series as well. The tests stop with BRK, if the opcode $CB does not work as expected. Successful operation ends in RTS. As the tests are very slow, they print dots on the screen while running so that you know that the machine has not jammed. On computers running at 1 MHz, the first test prints approximately one dot every four seconds and a total of 2048 dots, whereas the second one prints half that amount, one dot every seven seconds. If the tests fail on your machine, please let us know your processor's part number and revision. If possible, save the executable (after it has stopped with BRK) under another name and send it to us so that we know at which stage the program stopped. The following program is a Commodore 64 executable that Marko M"akel"a developed when trying to find out how the V flag is affected by SBX. (It was believed that the SBX affects the flag in a weird way, and this program shows how SBX sets the flag differently from SBC.) You may find the subroutine at $C150 useful when researching other undocumented instructions' flags. Run the program in a machine language monitor, as it makes use of the BRK instruction. The result tables will be written on pages $C2 and $C3. begin 644 sbx-c100 M`,%XH`",#L&,$,&,$L&XJ8*B@LL7AOL(:(7\N#BM#L$M$,'M$L$(Q?OP`B@` M:$7\\`,@4,'N#L'0U.X0P=#/SB#0[A+!T,<``````````````)BJ\!>M#L$M L$,'=_\'0":T2P=W_PM`!8,K0Z:T.P2T0P9D`PID`!*T2P9D`PYD`!