User Tools

Site Tools



This shows you the differences between two versions of the page.

Link to this comparison view

base:6510_8502_undocumented_commands [2015-04-17 04:30]
base:6510_8502_undocumented_commands [2015-04-17 04:30] (current)
Line 1: Line 1:
 +====== 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
 +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
 +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
 + and
 +begin 644 sbx
 +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
 +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
 +Other undocumented instructions usually cause two preceding opcodes
 +being executed. However 'NOP' seems to completely disappear from 'SBC'
 +code $EB.
 +The most difficult to comprehend are the rest of the instructions
 +located on the '$0B' line.
 +All the instructions located at the positive (left) side of this line
 +should rotate either memory or the accumulator, but the addressing
 +mode turns out to be immediate! No problem. Just read the operand, let
 +it be ANDed with the accumulator and finally use accumulator
 +addressing mode for the instructions above them.
 +/* This part of the document is not accurate.  You can
 +   read it as a fairy tale, but do not count on it when
 +   performing your own measurements. */
 +The rest two instructions on the same line, called 'ANE' and 'LXA'
 +($8B and $AB respectively) often give quite unpredictable results.
 +However, the most usual operation is to store ((A | #$ee) & X & #$nn)
 +to accumulator. Note that this does not work reliably in a real 64!
 +In the Commodore 128 the opcode $8B uses values 8C, CC, EE, and
 +occasionally 0C and 8E for the OR instead of EE,EF,FE and FF used in
 +the C64. With a C128 running at 2 MHz #$EE is always used.  Opcode $AB
 +does not cause this OR taking place on 8502 while 6510 always performs
 +it. Note that this behaviour depends on processor and/or video chip
 +Let's take a closer look at $8B (6510).
 +        A <- X & D & (A | VAL)
 +        where VAL comes from this table:
 +       X high   D high  D low   VAL
 +        even     even    ---    $EE (1)
 +        even     odd     ---    $EE
 +        odd      even    ---    $EE
 +        odd      odd      0     $EE
 +        odd      odd     not 0  $FE (2)
 +(1) If the bottom 2 bits of A are both 1, then the LSB of the result may
 +    be 0. The values of X and D are different every time I run the test.
 +    This appears to be very rare.
 +(2) VAL is $FE most of the time. Sometimes it is $EE - it seems to be random,
 +    not related to any of the data. This is much more common than (1).
 +  In decimal mode, VAL is usually $FE.
 +Two different functions have been discovered for LAX, opcode $AB. One
 +is A = X = ANE (see above) and the other, encountered with 6510 and
 +8502, is less complicated A = X = (A & #byte). However, according to
 +what is reported, the version altering only the lowest bits of each
 +nybble seems to be more common.
 +What happens, is that $AB loads a value into both A and X, ANDing the
 +low bit of each nybble with the corresponding bit of the old
 +A. However, there are exceptions. Sometimes the low bit is cleared
 +even when A contains a '1', and sometimes other bits are cleared. The
 +exceptions seem random (they change every time I run the test). Oops -
 +that was in decimal mode. Much the same with D=0.
 +What causes the randomness?  Probably it is that it is marginal logic
 +levels - when too much wired-anding goes on, some of the signals get
 +very close to the threshold. Perhaps we're seeing some of them step
 +over it. The low bit of each nybble is special, since it has to cope
 +with carry differently (remember decimal mode). We never see a '0'
 +turn into a '1'.
 +Since these instructions are unpredictable, they should not be used.
 +There is still very strange instruction left, the one named SHA/X/Y,
 +which is the only one with only indexed addressing modes. Actually,
 +the commands 'SHA', 'SHX' and 'SHY' are generated by the indexing
 +While using indexed addressing, effective address for page boundary
 +crossing is calculated as soon as possible so it does not slow down
 +operation. As a result, in the case of SHA/X/Y, the address and data
 +are processed at the same time making AND between them to take place.
 +Thus, the value to be stored by SAX, for example, is in fact (A & X &
 +(ADDR_HI + 1)).  On page boundary crossing the same value is copied
 +also to high byte of the effective address.
base/6510_8502_undocumented_commands.txt ยท Last modified: 2015-04-17 04:30 (external edit)