<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>
Date   : Sat, 16 Jul 1994 22:20:09 EST
From   : Stephen Quan <quan@...>
Subject: more on ADC lookup tables.

Hi, I have been looking at lookup tables for

  1. ADC's BCD arithmetic
  2. ADC's status register

I have already covered my technique in 1 and 2, but today I have
some real example code of this!  :-)

For BCD addition, I have

    A2 = lo_bcd_ADC[sum = (A & 15) + (M & 15) + get_C()] ^
           hi_bcd_ADC[sum = (A >> 4) + (M >> 4) + lo_bcd_ADC_carry[sum]];

Firstly, I have two lookup tables that handle the low-nibble addition

         lo_bcd_ADC[32]
         lo_bcd_ADC_carry[32]

which is indexed by the sum of the low nibbles of A and M with C.
These tables contain 32 numbers in them!  They are small!  :-)
Then I have the same two tables but reserved for hi-nibble addition

         hi_bcd_ADC[32]
         hi_bcd_ADC_carry[32]

In coding this, I have noted that hi_bcd_ADC_carry and lo_bcd_ADC_carry
are exactly the same.  The complete lookup tables are given at the end
of this document.

Also, I have decided to look at updating the status register

    if (hi_bcd_ADC_carry[sum])
      SR = (SR & ~NVZC_msk) ^ NVZC[beforeNZ[A] ^ afterNZ[A2]];
    else
      SR = (SR & ~NVZC_msk) ^ NVZ[beforeNZ[A] ^ afterNZ[A2]];

Basically, calculating the status register was actually easier to
understand than the above.  We already have C, it's hi_bcd_ADC_carry[sum].
N and Z are pretty straight forward, as a matter of fact I had NZ
coming out automatically from the tables I used for DEC.  I think I
posted the table previously as P_DEC.  Since then I have renamed that
table as NZ_lookup, and have statements like

   P = P & ~NZ_msk | NZ_lookup[--X];           /* DEX */
   P = P & ~NZ_msk | NZ_lookup[++Y];           /* INY */
   P = P & ~NZ_msk | NZ_lookup[A=immediate()]; /* LDA #immediate. */

Which leaves the problem of how to obtain V???  As it turns out,

   V = (Nbefore != Nafter)

You may have to try out a few examples before you'll see this!

In my C lookup-table implementation, I have everything being looked
up and very few places where I do actual arithmetic.  I have many
redundancies in my lookup tables, but I did this deliberately to
cut down the amount of C code required.

      beforeNZ[A]

I am only really interested in the N-before and N-after, but I thought,
whilst I am at it, I can go off and work out Z-before and Z-after at
now cost in speed.  ie. I also have

      afterNZ[A2]

I also decided that beforeNZ[A] will have the NZ bits moved to bits 1
and bit 0.  (Z-before is bit 0, N-before is bit 1).  So that with
afterNZ[A2] I can have NZ bits moved to bits 3 and bits 2. (Z-after
is bit 3 and N-after is bit 2).

     beforeNZ[A] ^ afterNZ[A2]

Therefore beforeNZ[A] ^ afterNZ[A2] will be a number between 0 to 15.
I can construct a lookup table that turns this into a V value.  Again,
being redundant, I decided to have a NVZ lookup table

     NVZ[beforeNZ[A] ^ afterNZ[A2]]

Whereby all status bits for N, Z and V are now in the correct positions.
Also I have a duplicate of this table which simply has the carry bit
always set

     NVZC[beforeNZ[A] ^ afterNZ[A2]]

Wrapping everything together I get the final version of updating the
status register.

    if (hi_bcd_ADC_carry[sum])
      SR = (SR & ~NVZC_msk) ^ NVZC[beforeNZ[A] ^ afterNZ[A2]];
    else
      SR = (SR & ~NVZC_msk) ^ NVZ[beforeNZ[A] ^ afterNZ[A2]];


My complete definition for my ADC macro is :

#define ADC(Mfunc) \
  { \
    register BYTE sum; \
    register BYTE A2; \
    register BYTE M; \
 \
    if (SR & D_msk) \
    { \
      M = Mfunc; \
      A2 = lo_bcd_ADC[sum = (A & 15) + (M & 15) + get_C()] ^ \
             hi_bcd_ADC[sum = (A >> 4) + (M >> 4) + lo_bcd_ADC_carry[sum]]; \
      if (hi_bcd_ADC_carry[sum]) \
        SR = (SR & ~NVZC_msk) ^ NVZC[beforeNZ(A) ^ afterNZ(A2)]; \
      else \
        SR = (SR & ~NVZC_msk) ^ NVZ[beforeNZ(A) ^ afterNZ(A2)]; \
    } \
    else \
    { \
      A2 = A + M + get_C(); \
      if (A2 < A) \
        SR = (SR & ~NVZC_msk) ^ NVZC[beforeNZ(A) ^ afterNZ(A2)]; \
      else \
        SR = (SR & ~NVZC_msk) ^ NVZ[beforeNZ(A) ^ afterNZ(A2)]; \
    }

And my lookup tables are :

  /*----------------------------------------------------------------------*/
  /* Lookup table for ADC in BCD mode.                                    */
  /*----------------------------------------------------------------------*/

  static BYTE lo_bcd_ADC[32]
  {
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
    0x08,0x09,0x00,0x01,0x02,0x03,0x04,0x05,
    0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,
    0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05
  };

  static BYTE lo_bcd_ADC_carry[32]
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,
    0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
    0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01
  };

  static BYTE hi_bcd_ADC[32]
  {
    0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,
    0x80,0x90,0x00,0x10,0x20,0x30,0x40,0x50,
    0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,
    0xe0,0xf0,0x00,0x10,0x20,0x30,0x40,0x50
  };

  static BYTE hi_bcd_ADC_carry[32]
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,
    0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
    0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01
  };

  static BYTE beforeNZ[256]
  {
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02
  };

  static BYTE afterNZ[256]
  {
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
  };

  static BYTE NVZ[16]
  {
    0x00,0x00,0x40,0x40,
    0x02,0x02,0x42,0x42,
    0xc0,0xc0,0x80,0x80,
    0xc2,0xc2,0x82,0x82
  };

  static BYTE NVZC[16]
  {
    0x01,0x01,0x41,0x41,
    0x03,0x03,0x43,0x43,
    0xc1,0xc1,0x81,0x81,
    0xc3,0xc3,0x83,0x83
  };

BTW, I have yet still to try this out myself.  All of the above code
is sitting in my emulator but is still commented.  I will be uncommented
them soon and see how they perform!
-- 
Stephen Quan (quan@...                 ), SysAdmin, Analyst/Programmer.
Centre for Spatial Information Studies, University of Tasmania, Hobart.
GPO BOX 252C, Australia, 7001.  Local Tel: (002) 202898 Fax: (002) 240282
International Callers use +6102 instead of (002).
<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>