Re: Update on emulating a paddle on the C64.

From: Greg King (gngking_at_erols.com)
Date: 2004-12-13 08:38:59

From: Jim Brain; on Date: December 09, 2004, 03:19 PM -0500
>
> > Is that sign-inversion necessary?  If the code to subtract the old
> > counter value from the new one is less efficient, then can't you use
> > the negative difference directly?  (If it's greater than -7000, then,
> > compare it to -4096.)
>
> Dunno, let me see:
>
> void calc(unsigned int old, unsigned int new) {
>   unsigned int tmp;
>   if (new < old) {
>     tmp=old-new;
>   } else {
>     tmp=new-old;
>   }
>   if (tmp < 7000) {
> ...
>   }
> }
>
> ... Is the old code.
>
> void calc(unsigned int old, unsigned int new) {
>   int tmp;
>   tmp=new-old;
>   if (tmp > -7000 && tmp < 7000) {
> ...
>   }
> }
>
> The corner case is when the counter is at 65535 (for example), and it
> wraps, to 4095.
>
> 4095-65535 = -61440 -> (signed int) -4095 (I think...)
>
> It would seem to work, and it'd be a bit faster, but someone needs to
> check my math.  I think the intermediate result would be stuffed into 16
> bits, and that would normalize to -4095, but someone needs to verify.

There are two problems with my questions:

1. I didn't know that you're writing the code in the C language.  I had
assumed that you were using assembly language. (Silly me -- I should have
known it, from a previous message of yours.)

2. I had forgotten that the free-running timer-counter wraps around.

Those two revelations change everything!  First, they raise a new question:

How wide is the "int" type in your micro-controller's C compiler?

In the rest of this letter, I will assume that it's 16 bits.

Second, the calc function must use "clock arithmetic" because of that
wrap-around.  For example, if the old value is 65532, and the new value is
5, then the (16-bit) distance between them is 9, not +/- 65527.
Fortunately, as Spiro said, two's-complement arithmetic, working in
unsigned variables, does what you need [a signed 16-bit -65527, when cast
into (unsigned), is 9].  So, calc() should be:

void calc(unsigned int old, unsigned int new) {
  unsigned int tmp;
  tmp = new - old;
  if (tmp < 7000 && tmp != 0) {
    if (tmp < 4096) {
      /* Run faster. */
      ...
    } else if (tmp > 4096) {
      /* Run slower. */
      ...
    }
  }
}

That "tmp != 0" catches the case when the counter wraps completely around
to its original value (the distance actually is 65536).


       Message was sent through the cbm-hackers mailing list

Archive generated by hypermail pre-2.1.8.