text: /*****************************************************************************\
  ** fire test program for cc65.                                               **
  **                                                                           **
  ** (w)2002 by groepaz/hitmen                                                 **
  **                                                                           **
  ** Cleanup and porting by Ullrich von Bassewitz.                             **
  ** 2004-06-08, Greg King                                                     **
  **                                                                           **
  \*****************************************************************************/
  
  
  
  /* sync page-flipping to vertical blank */
  /* #define DOVSYNC */
  
  #include <stdlib.h>
  #include <string.h> /* for memset */
  #include <time.h>
  #include <conio.h>
  
  
  
  #if defined(__C64__)
  #  define BUFFER                0x0400
  #  define SCREEN1               0xE000
  #  define SCREEN2               0xE400
  #  define CHARSET               0xE800
  #  define COLORRAM              0xD800
  #  define outb(addr,val)        (*(addr) = (val))
  #  define inb(addr)             (*(addr))
  #elif defined(__C128__)
  #  define BUFFER                0x0400
  #  define SCREEN1               0xE000
  #  define SCREEN2               0xE400
  #  define CHARSET               0xE800
  #  define COLORRAM              0xD800
  #  define outb(addr,val)        (*(addr) = (val))
  #  define inb(addr)             (*(addr))
  #elif defined(__CBM510__)
  #  define BUFFER                0xF800
  #  define SCREEN1               0xF000
  #  define SCREEN2               0xF400
  #  define CHARSET               0xE000
  #  define COLORRAM              0xD400
  #  define outb(addr,val)        pokebsys ((unsigned)(addr), val)
  #  define inb(addr)             peekbsys ((unsigned)(addr))
  #endif
  
  
  
  /* Values for the VIC address register to switch between the two pages */
  #define PAGE1                   ((SCREEN1 >> 6) & 0xF0) | ((CHARSET >> 10) & 0x0E)
  #define PAGE2                   ((SCREEN2 >> 6) & 0xF0) | ((CHARSET >> 10) & 0x0E)
  
  
  
  /* Use static local variables for speed */
  #pragma static-locals (1);
  
  
  
  #ifdef DOVSYNC
  #  define waitvsync() while ((signed char)VIC.ctrl1 >= 0)
  #else
  #  define waitvsync()
  #endif
  
  
  
  static void makechar (void)
  {
      static const unsigned char bittab[8] = {
          0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
      };
      register char *font;
      register unsigned char i, ii, b, bc;
      unsigned char c;
  
      gotoxy (0, 1);
  
      for (font = (char*)CHARSET; font != (char*)(CHARSET+(1*8)); ++font) {
          *font = 0x00;
      }
      for (font = (char*)(CHARSET+(64*8)); font != (char*)(CHARSET+(256*8)); ++font) {
          *font = 0xff;
      }
  
  
      for (c = 0; c < 0x40; ++c) {
          bc = 0;
          for (i = 0; i < 8; i++){
              b = 0;
              for (ii = 0; ii < 8; ii++) {
                  bc += c;
                  if (bc > 0x3f) {
                      bc = bc - 0x40;
                      b += bittab[(ii + (i & 1)) & 0x7];
                  }
              }
              ((unsigned char*)CHARSET + (1 * 8)) [(c * 8) + i] = b;
          }
          if ((c & 0x07) == 0) {
              cputc ('.');
          }
      }
  }
  
  
  
  static void fire (unsigned screenbase)
  {
      register char* screen;
      register char* buffer;
      register char c;
  
      screen = (char*) screenbase;
      buffer = (char*) BUFFER;
  
      while (buffer != (char*) (BUFFER + (24 * 40))) {
          c = (buffer[40-1] + buffer[40-1] + buffer[40] + buffer[41]) / 4;
          if (c > 2) {
              c -= 3;
          }
          *screen = *buffer = c;
          ++screen;
          ++buffer;
      }
  
      screen = (char*) (screenbase + (23 * 40));
      buffer = (char*) (BUFFER + (23 * 40));
  
      for(; buffer != (char*)(BUFFER+(25*40)); ++screen, ++buffer) {
          *screen = *buffer = 0x30 + (inb (&SID.noise) >> 4);
      }
  }
  
  
  
  int main (void)
  {
      unsigned char border;
      unsigned char background;
      unsigned char text;
      unsigned char v;
      clock_t       t;
      unsigned long f = 0;
      unsigned long sec;
      unsigned      sec10;
      unsigned long fps;
      unsigned      fps10;
      int           i;
  
  #if defined(__C64__)
      unsigned char block;
  #endif
  #if defined(__C128__)
      unsigned char block;
      unsigned char initflag;
      unsigned char graphflag;
  #endif
  
      /* Noise on channel 3 for random numbers  */
      outb (&SID.v3.freq, 0xffff);
      outb (&SID.v3.ctrl, 0x80);
  
      clrscr ();
      cprintf ("Making charset, mompls");
      makechar ();
  
      /* Set the border and background colors */
      border     = bordercolor (COLOR_BLACK);
      background = bgcolor (COLOR_BLACK);
      text       = textcolor (COLOR_BLACK);
      clrscr ();
  
      for(i = 0; i != 0x400; i++) {
          *((char *)(i + BUFFER))  = 0;
          *((char *)(i + SCREEN1)) = 0;
          *((char *)(i + SCREEN2)) = 0;
          outb ((char*)(i + COLORRAM), COLOR_YELLOW);
      }
  
  #if defined(__C64__) || defined(__C128__)
      /* Move the VIC 16K block */
      block = inb (&CIA2.pra);
      outb (&CIA2.pra, (block & 0xFC) | ((SCREEN1 >> 14) ^ 0x03));
  #endif
  #if defined(__C128__)
      /* Save and change some flags, so that kernal/basic interrupt handler will
      ** not interfere with our routine.
      */
      initflag = *(unsigned char*) 0xA04;
      *(unsigned char*) 0xA04 &= 0xFE;
      graphflag = *(unsigned char*) 0xD8;
      *(unsigned char*) 0xD8 = 0xFF;
  #endif
  
      /* Remember the VIC address register */
      v = inb (&VIC.addr);
  
      /* Run the demo until a key was hit */
      t = clock ();
      while (!kbhit()) {
          /* Build page 1, then make it visible */
          fire (SCREEN1);
          waitvsync ();
          outb (&VIC.addr, PAGE1);
  
          /* Build page 2, then make it visible */
          fire (SCREEN2);
          waitvsync ();
          outb (&VIC.addr, PAGE2);
  
          /* Count frames */
          f += 2;
      }
      t = clock() - t;
  
      /* Switch back the VIC screen */
      outb (&VIC.addr, v);
  
  #if defined(__C64__) || defined(__C128__)
      /* Move back the VIC 16K block */
      outb (&CIA2.pra, block);
  #endif
  #if defined(__C128__)
      /* Restore the flags */
      *(unsigned char*) 0xA04 = initflag;
      *(unsigned char*) 0xD8  = graphflag;
  #endif
  
      /* Fetch the character from the keyboard buffer and discard it */
      (void) cgetc();
  
      /* Reset screen colors */
      bordercolor (border);
      bgcolor (background);
      textcolor (text);
      clrscr ();
  
      /* Calculate stats */
      sec   = (t * 10) / CLK_TCK;
      sec10 = sec % 10;
      sec  /= 10;
      fps   = (f * (CLK_TCK * 10)) / t;
      fps10 = fps % 10;
      fps  /= 10;
  
      /* Output stats */
      gotoxy (0, 0); cprintf ("time  : %lu.%us", sec, sec10);
      gotoxy (0, 1); cprintf ("frames: %lu", f);
      gotoxy (0, 2); cprintf ("fps   : %lu.%u", fps, fps10);
  
      /* Wait for a key, then end */
      cputsxy (0, 4, "Press any key when done...");
      (void) cgetc ();
  
      /* Done */
      return EXIT_SUCCESS;
  }
  
  
  
  