[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 6502 illegal opcodes questions



Linards Ticmanis <ticmanis@gmx.de> writes:

> Scott Hemphill wrote:
> >> I'm still not quite happy with some ugly details that I haven't seen
> >> documented too well:
> >>
> >> 1.) Operation of ARR ($6B) when the decimal flag is SET.
> >>
> >> 2.) Exact operation of decimal mode ADC and SBC in both the 6502 and
> >> the 65C02.
> > I have C code which emulates ADC and SBC for the 65C02 for all
> > values of
> > the argments and flags.
> 
> Thanks Scott! I've copied the algorithm from VICE for now, but that is
> of course NMOS 6502 only, since Commodore never switched to the 65C02
> chips for their own computers. Thus I am very interested in your code
> for better coverage of 65C02. Would you mind posting it here or
> mailing it to me? My From address is valid.

OK, here it is.  A is the accumulator, b is the argument (an unsigned 8-bit
quantity).  V, D, and C are booleans which represent the state of the
corresponding flags.  NZ is a byte which holds the state of the N and Z
flags.  The N flag is set if (NZ & 0x80) is true, and the Z flag is set
if (NZ == 0) is true.  w is a 16-bit unsigned scratch location.

These instructions were tested by running a PRODOS program which combined
each of the 256 possible accumulator values with the 256 argument values.
The 64K combinations were output as a 128K file containing a one-byte result
and one byte of flags.  The program was edited to produce 8 different
versions:  (initial C set/clear)x(initial D set/clear)x(ADC/SBC).  The
program versions were run on a Laser 128/EX and on an emulator, and the
results compared.  (All of this was done about 20 years ago.)

#define ADC()                                        \
      do {                                           \
        if ((A^b) & 0x80) V = 0; else V = 1;         \
        if (D) {                                     \
          w = (A & 0xf) + (b & 0xf) + C;             \
          if (w >= 10) w = 0x10 | ((w+6)&0xf);       \
          w += (A & 0xf0) + (b & 0xf0);              \
          if (w >= 160) {                            \
            C = 1;                                   \
            if (V && w >= 0x180) V = 0;              \
            w += 0x60;                               \
          } else {                                   \
            C = 0;                                   \
            if (V && w < 0x80) V = 0;                \
          }                                          \
        } else {                                     \
          w = A + b + C;                             \
          if (w >= 0x100) {                          \
            C = 1;                                   \
            if (V && w >= 0x180) V = 0;              \
          } else {                                   \
            C = 0;                                   \
            if (V && w < 0x80) V = 0;                \
          }                                          \
        }                                            \
        A = (byte)w;                                 \
        NZ = A;                                      \
      } while (0)

#define SBC()                                        \
      do {                                           \
        if ((A^b) & 0x80) V = 1; else V = 0;         \
        if (D) {                                     \
          int tmp;                                   \
          tmp = 0xf + (A & 0xf) - (b & 0xf) + C;     \
          if (tmp < 0x10) {                          \
            w = 0;                                   \
            tmp -= 6;                                \
          } else {                                   \
            w = 0x10;                                \
            tmp -= 0x10;                             \
          }                                          \
          w += 0xf0 + (A & 0xf0) - (b & 0xf0);       \
          if (w < 0x100) {                           \
            C = 0;                                   \
            if (V && w < 0x80) V = 0;                \
            w -= 0x60;                               \
          } else {                                   \
            C = 1;                                   \
            if (V && w >= 0x180) V = 0;              \
          }                                          \
          w += tmp;                                  \
        } else {                                     \
          w = 0xff + A - b + C;                      \
          if (w < 0x100) {                           \
            C = 0;                                   \
            if (V && w < 0x80) V = 0;                \
          } else {                                   \
            C = 1;                                   \
            if (V && w >= 0x180) V = 0;              \
          }                                          \
        }                                            \
        A = (byte)w;                                 \
        NZ = A;                                      \
      } while (0)


-- 
Scott Hemphill	hemphill@alumni.caltech.edu
"This isn't flying.  This is falling, with style."  -- Buzz Lightyear