base:6510_8502_undocumented_commands
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | base:6510_8502_undocumented_commands [2015-04-17 04:30] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
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. | ||
+ | on the data that was left on the bus by the VIC-II. | ||
+ | |||
+ | LXA $AB | ||
+ | Alternate: A = X = (A & #byte) | ||
+ | |||
+ | TXA and TAX have to be responsible for these. | ||
+ | |||
+ | SHA $93, | ||
+ | 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 ' | ||
+ | which is in the STORE section (opcodes $A0...$BF), stores the result | ||
+ | of (A & X) by this way. | ||
+ | |||
+ | More fortunate is its opposite, ' | ||
+ | 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' | ||
+ | V flag is the result of an Exclusive OR operation between the bit 6 | ||
+ | and the bit 5 of the result. | ||
+ | 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, | ||
+ | illustrates the ARR operation in Decimal mode: | ||
+ | |||
+ | unsigned | ||
+ | | ||
+ | AL, /* low nybble of accumulator */ | ||
+ | AH, /* high nybble of 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 " | ||
+ | A = (A & 0xF0) | ((A + 6) & 0xF); | ||
+ | |||
+ | if (C = AH + (AH & 1) > 5) /* Set the Carry flag. */ | ||
+ | A = (A + 0x60) & 0xFF; /* BCD " | ||
+ | |||
+ | |||
+ | |||
+ | $CB SBX X <- (A & X) - Immediate | ||
+ | |||
+ | The ' | ||
+ | is a combination of the subtraction of accumulator and parameter, as | ||
+ | in the ' | ||
+ | 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 ' | ||
+ | (A & X) - Immediate. | ||
+ | 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. | ||
+ | |||
+ | | ||
+ | |||
+ | begin 644 vsbx | ||
+ | M`0@9$, | ||
+ | M^QBE^VEZJ+$KH# | ||
+ | JD-Z@/ | ||
+ | ` | ||
+ | end | ||
+ | |||
+ | and | ||
+ | |||
+ | begin 644 sbx | ||
+ | M`0@9$, | ||
+ | MA? | ||
+ | MV# | ||
+ | 9*Y# | ||
+ | ` | ||
+ | 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, | ||
+ | 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' | ||
+ | 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" | ||
+ | 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' | ||
+ | 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`, | ||
+ | M: | ||
+ | L$,' | ||
+ | ` | ||
+ | end | ||
+ | |||
+ | |||
+ | Other undocumented instructions usually cause two preceding opcodes | ||
+ | being executed. However ' | ||
+ | code $EB. | ||
+ | |||
+ | The most difficult to comprehend are the rest of the instructions | ||
+ | located on the ' | ||
+ | |||
+ | All the instructions located at the positive (left) side of this line | ||
+ | should rotate either memory or the accumulator, | ||
+ | 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. | ||
+ | |||
+ | RELIGION_MODE_ON | ||
+ | /* This part of the document is not accurate. | ||
+ | read it as a fairy tale, but do not count on it when | ||
+ | | ||
+ | |||
+ | The rest two instructions on the same line, called ' | ||
+ | ($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 | ||
+ | revision. | ||
+ | |||
+ | 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 | ||
+ | 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 ' | ||
+ | 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? | ||
+ | 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 ' | ||
+ | turn into a ' | ||
+ | |||
+ | Since these instructions are unpredictable, | ||
+ | |||
+ | 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 ' | ||
+ | algorithm. | ||
+ | |||
+ | 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. | ||
+ | |||
+ | RELIGION_MODE_OFF | ||
+ | </ | ||
base/6510_8502_undocumented_commands.txt · Last modified: 2015-04-17 04:30 by 127.0.0.1