#define MAX_BRIGHTNESS 255U

#define SETW(what, val) what = val
#define SET(what, val) what = val
#define GET(what) what

void cDelay (unsigned int units)
{
   volatile unsigned int i;

   for (i = 0; i < units; i++) {
      asm ("nop");
   }
}

static void cstrcpy (char *dest, char *src)
{
   char c;

   do {
      c = *src++;
      *dest++ = c;
   }
   while (c != '\0');
}

static int random (void)
{
   static unsigned long rseed;

   return (int) (rseed = (rseed * 2053UL) + 13849UL);
}

#ifdef NEVER
// this is quite a "C" optimized version of print_sync
// it is actually FASTER than
// the "not very optimized" assembler include!
// (-O3 and no_frame_pointer)

void
draw_synced_list_c (signed char *u, signed int y, signed int x,
		    unsigned int scaleMove, unsigned int scaleList)
{

#define ZERO_DELAY 5

   do {
      // resync / startsync
      VIA_shift_reg = 0;	// all output is BLANK
      //asm ( "clra" );
      //asm ( "sta 0xd00a");
      // move to zero
      VIA_cntl = (int) 0xcc;	// zero the integrators 
      VIA_port_a = 0;		// reset integrator offset 
      VIA_port_b = (int) 0 b10000010;

      VIA_t1_cnt_lo = scaleMove;

      // delay, till beam is at zero
      // volatile - otherwise delay loop does not work with -O
      for (volatile signed int b = ZERO_DELAY; b > 0; b--) ;
      VIA_port_b = (int) 0 b10000011;

      // move to "location"
      VIA_port_a = y;		// y pos to dac
      VIA_cntl = (int) 0xce;	// disable zero, disable all blank
      VIA_port_b = 0;		// mux enable, dac to -> integrator y (and x)
      //VIA_shift_reg = 0;            // all output is BLANK
      //asm ( "clra" );
      //asm ( "sta 0xd00a");
      VIA_port_b = 1;		// mux disable, dac only to x
      VIA_port_a = x;		// dac -> x
      VIA_t1_cnt_hi = 0;	// start timer

      // this can be done before the wait loop
      // since it only fills the latch, not the actual timer!
      VIA_t1_cnt_lo = scaleList;
      u += 3;

      // moving test for yx== 0 into the move delay
      if ((*(u - 2) != 0) || (*(u - 1) != 0))
      {
	 while ((VIA_int_flags & 0x40) == 0) ;	// wait till timer finishes

	 // internal moveTo
	 VIA_port_a = *(u - 2);	// y pos to dac
	 VIA_cntl = (int) 0xce;	// disable zero, disable all blank
	 VIA_port_b = 0;	// mux enable, dac to -> integrator y (and x)
         //VIA_shift_reg = 0;            // all output is BLANK
         //asm ( "clra" );
         //asm ( "sta 0xd00a");
	 VIA_port_b = 1;	// mux disable, dac only to x
	 VIA_port_a = *(u - 1);	// dac -> x
	 VIA_t1_cnt_hi = 0;	// start timer
	 while ((VIA_int_flags & 0x40) == 0) ;	// wait till timer finishes
      }
      else
      {
	 while ((VIA_int_flags & 0x40) == 0) ;	// wait till timer finishes
      }
      while (1)
      {
	 if (*u < 0)		// draw line
	 {
            // draw a vector
	    VIA_port_a = *(1 + u);	// y pos to dac
	    VIA_port_b = 0;	// mux enable, dac to -> integrator y (and x)
	    VIA_port_b = 1;	// mux disable, dac only to x
	    VIA_port_a = *(2 + u);	// dac -> x
	    VIA_t1_cnt_hi = 0;	// start timer
	    VIA_shift_reg = (int) 0xff;	// draw complete line
	    while ((VIA_int_flags & 0x40) == 0) ;	// wait till timer
							// finishes
	    VIA_shift_reg = 0;	// all output is BLANK
            //asm ( "clra" );
            //asm ( "sta 0xd00a");
	 }

	 else if (*u == 0)	// moveTo
	 {
	    if ((*(u + 1) != 0) || (*(u + 2) != 0))
	    {

	       // internal moveTo
	       VIA_port_a = *(1 + u);	// y pos to dac
	       VIA_cntl = (int) 0xce;	// disable zero, disable all blank
	       VIA_port_b = 0;	// mux enable, dac to -> integrator y (and x)
               //VIA_shift_reg = 0;            // all output is BLANK
               //asm ( "clra" );
               //asm ( "sta 0xd00a");
	       VIA_port_b = 1;	// mux disable, dac only to x
	       VIA_port_a = *(2 + u);	// dac -> x
	       VIA_t1_cnt_hi = 0;	// start timer
	       while ((VIA_int_flags & 0x40) == 0) ;	// wait till timer
							// finishes
	    }
	 }

	 else
	 {
	    break;
	 }
	 u += 3;
      }
   }
   while (*u != 2);
}
#endif /* */

static void cMov_Draw_VLc_a (signed char *vList)
{
   register int count = *(vList) - 1;	// count in list

   SET (dp_VIA_port_a, *(1 + vList));	// y pos to dac
   SET (dp_VIA_cntl, 0xce);	// disable zero, disable all blank
   SET (dp_VIA_port_b, 0);	// mux enable, dac to -> integrator y (and x)
   SET (dp_VIA_port_b, 1);	// mux disable, dac only to x
   SET (dp_VIA_port_a, *(2 + vList));	// dac -> x
   SET (dp_VIA_t1_cnt_hi, 0);	// start timer
   vList += 3;
   while ((GET (dp_VIA_int_flags) & 0x40) == 0) ;	// wait till timer
   // finishes
   // This will have to be modified until you get reading to work...

   do {
      SET (dp_VIA_port_a, *(vList));	// first y coordinate to dac
      SET (dp_VIA_port_b, 0);	// mux enable, dac to -> integrator y (and x)
      SET (dp_VIA_port_b, 1);	// mux disable, dac only to x
      SET (dp_VIA_port_a, *(vList + 1));	// dac -> x
      SET (dp_VIA_shift_reg, 0xff);	// full "unblank" output
      SET (dp_VIA_t1_cnt_hi, 0);	// start timer
      vList += 2;
      while ((GET (dp_VIA_int_flags) & 0x40) == 0) ;	// wait till timer
							// finishes
      SET (dp_VIA_shift_reg, 0);	// output full blank
   }
   while (--count >= 0);	// loop thru all vectors
}

static void cMoveto_d (signed int y, signed int x)
{
   dp_VIA_port_a = y;		// y pos to dac
   dp_VIA_cntl = 0xce;		// disable zero, disable all blank
   dp_VIA_port_b = 0;		// mux enable, dac to -> integrator y (and x)
   dp_VIA_shift_reg = 0;	// all output is BLANK
   dp_VIA_port_b++;		// mux disable, dac only to x
   dp_VIA_port_a = x;		// dac -> x
   dp_VIA_t1_cnt_hi = 0;	// start timer
   while ((dp_VIA_int_flags & 0x40) == 0) ;	// wait till timer finishes
}

static void cIntensity_a (unsigned int i)
{
   Vec_Brightness = (int) i;
   SET (dp_VIA_port_a, (int) i);	// Store intensity in D/A
   SET (dp_VIA_port_b, 5);	// mux disabled channel 2
   SET (dp_VIA_port_b, 4);	// mux enable
   SET (dp_VIA_port_b, 1);	// turn off mux
}

static void cDraw_VLp (signed int *list)
{

   do
   {
      dp_VIA_port_a = *(list + 1);	// Send Y to A/D
      dp_VIA_port_b = 0;	// Enable mux dac goes to y and x integrators
      dp_VIA_port_b++;		// disable mux
      dp_VIA_port_a = *(list + 2);	// send x to A/D
      dp_VIA_t1_cnt_hi = 0;	// start timer (and movement)
      dp_VIA_shift_reg = (unsigned int) *list;	// *list; // shift reg =
						// pattern byte
      list = list + 3;
      while ((dp_VIA_int_flags & 0x40) == 0) ;	// wait till timer finishes
      dp_VIA_shift_reg = (int) 0x00;	// swithc light off
   }
   while (((signed int) (*list)) <= 0);
}

static void cReset0Ref ()
{
   SET (dp_VIA_cntl, 0xcc);	// enable zero, enable all blank

   // reset integrators
   SET (dp_VIA_port_a, 0);	// dac = 0
   SET (dp_VIA_port_b, 3);	// mux=1, disable mux
   SET (dp_VIA_port_b, 2);	// mux=1, enable mux
   SET (dp_VIA_port_b, 2);	// delay
   SET (dp_VIA_port_b, 1);	// disable mux
}

// The 'No BIOS' raster text printing is not working yet, and we are currently
// using the bios print_str - however it seems to be working for now...

#define Char_Table 0xF9F4L
#define Char_Table_End 0xFBD4L

void cPrint_Str (register void *volatile text)
{
   Vec_Str_Ptr = text;
   register int *charTable = (int *) (Char_Table - 0x20);	// Point to
								// start of
								// chargen
								// bitmaps
   dp_VIA_aux_cntl = 0x18;
   dp_VIA_port_a = 0;		// Clear D/A output
   dp_VIA_port_b = (int) 0x83;	// ramp off/on set mux to channel 1
   register int letter;

   while (1) {
      dp_VIA_port_b--;		// Enable mux
      dp_VIA_port_b++;		// Disable mux
      dp_VIA_port_b = (int) 0x81;	// Disable RAMP, set mux to channel
					// 0, disable mux
      dp_VIA_port_b = (int) 0x80;	// Enable mux
      dp_VIA_port_b++;		// Disable mux
      dp_VIA_port_a = Vec_Text_Width;	// Get text width -> Send it to the
					// D/A
      dp_VIA_port_b = 0x01;	// enable RAMP, disable mux

      goto overStep;

stepBack:
      dp_VIA_shift_reg = (unsigned int) *(charTable + letter);

overStep:
      letter = (int) *(((unsigned int *) text++));

      if (letter > 0)
	 goto stepBack;

      dp_VIA_port_b = (int) 0x81;	// disable mux, disable ramp
      dp_VIA_port_a = -dp_VIA_port_a;
      dp_VIA_port_b = 0x01;	// enable RAMP, disable mux
      if (((unsigned long) charTable) == (Char_Table_End - 0x20L))
	 break;
      charTable += 0x50;

   register volatile unsigned int size = (unsigned int) (((unsigned long) text) - ((unsigned long) Vec_Str_Ptr));

      size -= 2;
      size = size << 1;
      while (size-- > 0) ;
      dp_VIA_port_b = (int) 0x81;	// disable RAMP, disable mux
      dp_VIA_port_a = Vec_Text_Height;
      dp_VIA_port_b--;		// Enable mux
      dp_VIA_port_b = (int) 0x81;	// disable RAMP, disable mux
      dp_VIA_port_a = 0;
      dp_VIA_port_b = 0x01;	// enable RAMP, disable mux
      dp_VIA_port_b = (int) 0x81;	// disable RAMP, disable mux
      dp_VIA_port_b = 0x03;	// ENABLE RAMP ...
   }
   dp_VIA_aux_cntl = 0x98;
   cReset0Ref ();
}

#define scale(x) do { dp_VIA_t1_cnt_lo = (x); } while(0)

__attribute__ ((interrupt)) static void draw_graphics (void)
{
   int *vec;
   int row;

   if ((dp_VIA_int_flags & 0x20) == 0) {
      // for anything except the t2 timer we want to rti immediately.
      return;
   }
   Vec_Loop_Count++;
   dp_VIA_t2 = Vec_Rfrsh;
   dp_VIA_t1_cnt_lo = (unsigned int) 255;
   cMoveto_d (127, 127);
   dp_VIA_cntl = 0xcc;		// enable zero, enable all blank
   cMoveto_d (-128, -128);
   dp_VIA_cntl = 0xcc;		// enable zero, enable all blank
   dp_VIA_port_a = 0;		// dac = 0
   dp_VIA_port_b = 3;		// mux=1, disable mux
   dp_VIA_port_b = 2;		// mux=1, enable mux
   dp_VIA_port_b = 2;		// delay
   dp_VIA_port_b = 1;		// disable mux

   // graphics executed here.
   dp_VIA_aux_cntl = 0x98;
   Reset0Ref ();
   Print_Str_d (0, -70, DEMO);

   // BOUNCER
   cIntensity_a (MAX_BRIGHTNESS / 4);	/* set intensity of vector beam... */
   for (int i = 0; i < 7; i++) {
      scale (0x50);
      cDelay (1);
      SET (VIA_cntl, 0xCE);
      cMov_Draw_VLc_a ((void *) BouncerTitle[i]);
      SET (VIA_cntl, 0xCC);
   }

   vec = (int *) vector;
   for (row = 0; row < ASTEROIDS; row++) {
      cReset0Ref ();
      scale (0x58);
      cMoveto_d (y[row], x[row]);
      scale (0x04);
      cDraw_VLp (vec);
      vec += 3 * 8 + 1;
   }
}

#define IRQBASE 0xCBF8
unsigned long volatile *const IRQ = (unsigned long *) (IRQBASE + 1);
unsigned int volatile *const IRQ_INST = (unsigned int *) IRQBASE;

static int init (void);
static int loop (void);

int main (void)
{
   unsigned long frame;

   *IRQ_INST = (unsigned int) 0x7e;	// JMP ... this is actually code!,
					// first a JMP instruction
   *IRQ = (unsigned long) &draw_graphics;	// to Address
   (void) init ();

   // ensure timer is sensible to start with
   dp_VIA_t2 = Vec_Rfrsh;
   dp_VIA_int_enable |= 0x20;
   asm ("andcc #0xef");		// enable IRQ with 6809
   frame = Vec_Loop_Count = 0L;
   for (;;) {
      // Only display once every 1/50s in interrupt routine
      while (frame == Vec_Loop_Count)	/* wait */
	 ;
      frame = Vec_Loop_Count;
      (void) loop ();
   } return 1;			// cold reset - NOT REACHED
}