/**************************************************************************************\
*                                                                                      *
*               The Lisa Emulator Project  V1.0 ALPHA REL 2007.01.28                   *
*                             http://lisaem.sunder.net                                 *
*                                                                                      *
*                  Copyright (C) 1998, 2007 Ray A. Arachelian                          *
*                                All Rights Reserved                                   *
*                                                                                      *
*           This program is free software; you can redistribute it and/or              *
*           modify it under the terms of the GNU General Public License                *
*           as published by the Free Software Foundation; either version 2             *
*           of the License, or (at your option) any later version.                     *
*                                                                                      *
*           This program is distributed in the hope that it will be useful,            *
*           but WITHOUT ANY WARRANTY; without even the implied warranty of             *
*           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
*           GNU General Public License for more details.                               *
*                                                                                      *
*           You should have received a copy of the GNU General Public License          *
*           along with this program;  if not, write to the Free Software               *
*           Foundation, Inc., 59 Temple Place #330, Boston, MA 02111-1307, USA.        *
*                                                                                      *
*                   or visit: http://www.gnu.org/licenses/gpl.html                     *
*                                                                                      *
*                                                                                      *
*                               VIA 6522 Emulators                                     *
*                                                                                      *
*           these control the parallel interfaces for external profile, and            *
*           internal widget hard drives, the ADMP/Canon printers, the COPS             *
*           keyboard/mouse/clock controller, and expansion slot parallel cards.        *
*                                                                                      *
\**************************************************************************************/



// Reminder - must signal control codes to ProfileLoop for whatever Via!!!

/* VIA IER/IFR bits
 *
 *    bit#
 * 0  1    0 CA2 Active Edge
 * 1  2    1 CA1
 * 2  4    2 Shift Register
 * 3  8    3 CB2
 * 4  16   4 CB1
 * 5  32   5 Timeout of T2
 * 6  64   6 Timeout of T1
 * 7  128  7 Any enabled IRQ when in IFR, set/clear when in IER.
 *
 */

// Paralell port VIA PORT B bit definitions


    // 2004.07.26 Parallel Port Card: PB7 on VIA= Controller Reset. PB5==parity


 /*-----------------6/20/2004 10:18AM----------------
  * Expansion port VIA information:
  *
  * ROM is byte wide - odd addresses have data only
  * 2003c-2083b is ROM extracted by DTC.  Lower Via is at 2000, upper via is at 28000
  *
  * I need to know the spacing between VIA regs though.
  *
  * One of the routines clears regs at addresses off A0.
  * 70,68,58,60,0,8,10,18,38,30,40,48,58,50,60,8,10,18,30,38,40,48,50.  So it seems to be every 8 bytes
  * value 7F-> address 70.  Other values fed here: C0 and A0.
  *
  * ROM for 0 is at fc0000-fc1fff.
  *
  * expansion port slot addresses:
  *
  * fc0000-fc1fff low decode slot 1 (ROM lives here)
  * fc2000-fc3fff VIA's live here at offset 2000, and 2800
  *
  * fc4000-fc5fff low decode slot 2 (ROM?)
  * fc6000-fc7fff VIA's
  *
  * fc8000-fc9fff low decode slot 3 (ROM?)
  * fca000-fcbfff VIA's.
  *
  * Above is valid and verified from DTC's disassembly of this ROM
  *
  *
  * --------------------------------------------------*/


// clear CA1/CA2 on ORA/IRA access
#define  VIA_CLEAR_IRQ_PORT_A(x) { if (((via[x].via[PCR]>>1) & 7)!=1 &&                                      \
                                       ((via[x].via[PCR]>>1) & 7)!=3   )                                     \
                                            via[x].via[IFR] &=(0xff-VIA_IRQ_BIT_CA2-VIA_IRQ_BIT_CA1);        \
                                   via[x].ca1=0; via[x].ca2=0; if ( via[x].via[IFR]==128) via[x].via[IFR]=0;}
// clear Cb1/Cb2 on ORb/IRb access
#define  VIA_CLEAR_IRQ_PORT_B(x) { if (((via[x].via[PCR]>>5) & 7)!=1 &&                                      \
                                             ((via[x].via[PCR]>>5) & 7)!=3   )                               \
                                                  via[x].via[IFR] &=(0xff-VIA_IRQ_BIT_CB2-VIA_IRQ_BIT_CB1);  \
                                    via[x].cb1=0; via[x].cb2=0; if ( via[x].via[IFR]==128) via[x].via[IFR]=0;}
// clear SR irq on SR access
#define  VIA_CLEAR_IRQ_SR(x)     { via[x].via[IFR] &=!VIA_IRQ_BIT_SR; if (via[x].via[IFR]==128) via[x].via[IFR]=0; DEBUG_LOG(0,"SR IRQ on via %d cleared",x);}

// clear T1 irq on T1 read low or write high
#define  VIA_CLEAR_IRQ_T1(x)     { via[x].via[IFR] &=~VIA_IRQ_BIT_T1; if (via[x].via[IFR]==128) via[x].via[IFR]=0; DEBUG_LOG(0,"Timer1 IRQ on via %d cleared",x);}


// clear T2 irq on T2 read low or write high
#define  VIA_CLEAR_IRQ_T2(x)     { via[x].via[IFR] &=~VIA_IRQ_BIT_T2; if ( via[x].via[IFR]==128) via[x].via[IFR]=0; DEBUG_LOG(0,"Timer2 IRQ on via %d cleared",x);}


// write to IER - 0=disabled, 1=enabled. if write to IER with bit 7 is 0 - each "1" bit disables the irq.
// if bit 7 is 1 each 1 bit enables the corresponding IRQ
// if read, bit 7 will be 0, and all others will reflect their enabled/disabled state.
//
// IRQ= (ier & ifr & 127) ? 1:0;
//
// PCR bits
// 0 - CA1 IRQ control 0-negative edge, 1-positive edge
// 1,2,3- CA2 Control: 0-input negative active edge, 1 independent IRQ, 2-input positive, 3=indep. irq input positive
//                     4-handshake output, 5-pulse output, 6-low, 7-high
// 4-CB1 IRQ Control: 0-negative edge, 1=positive edge
// 5,6,7 - CB2 control - same as CA2 control.
//
//
// Handshake: CA2/CB2 mean data ready output, CA1, CB1 are inputs meaning "data taken" sent by peripheral


/*

dual parallel exp card
----------------------------------------------------
ca1=BSY link to pb1
ca2=pstrobe
cb1=lchk - check condition from device
cb2=parity error irq
pb0=OCD
pb1=bsy+ca1 (CA1 must be an input that says hold?)
pb2=Driver enable?
pb3=rrw (1=write)
pb4=cmd
pb5=parity reset on
pb6=parity data
pb7=parallel port controller reset

  Parallel Port VIA2 special lines
  VIA            Lisa
  PA0-PA7        DD0-DD7 Parallel Port Data Lines  (also used for contrast)
  CA2            !PSTROBE - Processor Strobe - (handshaking)
  CA1        +---BSY      - Input Busy Signal -- IRQ source!
  CB2        |   Monitor Parity Status of the interface
  CB1        |
  PB0        |   Open Cable Detect (peripheral attached) - 0 if connected to device, disconnected=1   *Confirmed*
  PB1        +---ProFile Busy if 1, 0 if available
  PB2            Driver Enable  - enables buffer drivers (transceivers) - enabled low - if PB2=1, no PA write to ProFile!
  PB3            Data Read/Write - 0=read, 1=write
  PB4            !CMD - output to peripheral
  PB5            Diagnostic PARITY Checking
  PB6            Floppy Disk Diag Input <- can be tied to Timer2
  PB7            Contrast Strobe - PA0-7 --> Contrast when PB2=1 and PB7=1.   -> Can be output of timer1 expiration

 Parallel Port via Parity
 CB1 is not connected, not connected on VIA1 either.
 CB2 is parity error input - Q output from U6E (Ls109 JKflop)
 CA2 is the clock input to this flop + also goes to PSTRB (parallel port strobe)
 CA2 handshaking is automatic.
 PB5 is parity input from LS280 adder



  COPS/Keyboard VIA1 lines

  KB PB0         Reset keyboard
  KB PB1-3       Speaker Volume
  KB PB4         Floppy FDIR input

  KB PB5         !PRES - Parity Reset (on KB controller) -> *** parallel port ***

  KB PB6         Cops Handshake  <- Can be tied to Timer2  (seen after LisaTest Parallel Port Test locking up VIA?)
  KB PB7         !CRES - Controller Reset -> parallel port -> can be output of Timer1 expiration
                 CHK - Check - processed by COPS - produces key code d000 0101 (d=1 on rising edge, 0 on falling edge)

  SR             Sound output (can be under control of Timer1 or system clock or Phi2 clock)

 Expansion port Parallel Cards do not swap PB7/PB6 lines, need to check out the exact pins


Lisa Parallel Port Card VIA Definitions
----------------------
PB7 -output- Controller Reset
PB5 -input-  parity error input  - also cb2????

Or is PB5 the actual parity and CB2 the error?
CB1=LCHK
PB0=LOCD
PB1+CA1=BUSY
CA2=Port Strobe
PB3=A+B Output from pin1 of LS245 which gets inputs from PA + port
PB2 looks like a latch enable
PB4 LCMD
PB3 = RRW
CB2 == PARITY MISMATCH ERROR IRQ

Input on !UCRES goes to PB5??? which also looks like parity input
Signal on PB7 will reset PB5 input

UPARITY is an input into PB6, so PB6 actually reads the parity bit on the port,
so it's important to present this data to PB6.  UPARITY is also an input to the
parity circuit (pin4 on LS280) - though not sure if this is an input or output
need to get the sheet for LS280's.  - confirmed pin4 is an input.
pin 5 is even pin 6 is odd. 1,2,8-13 are inputs.  Lisa uses pin 5 hence even
parity?
---------------------

 *
 *
 *
 */

#define IN_VIA6522_C
#include "vars.h"

extern void set_next_timer_id(uint8 x);

#define FIX_CLKSTOP_VIA_T1(x) \
            {  if (via[x].t1_e>-1 && via[x].t1_e<cpu68k_clocks_stop)                                  \
               {cpu68k_clocks_stop=via[x].t1_e; set_next_timer_id(CYCLE_TIMER_VIAn_T1_TIMER(x));}     }

#define FIX_CLKSTOP_VIA_T2(x) \
            {  if (via[x].t2_e>-1 && via[x].t2_e<cpu68k_clocks_stop)                                  \
               {cpu68k_clocks_stop=via[x].t2_e; set_next_timer_id(CYCLE_TIMER_VIAn_T2_TIMER(x));}     \
                DEBUG_LOG(0,"fix_clk_stop_via_t2(%d) now:%llx stop:%llx timer:%llx",x,cpu68k_clocks,cpu68k_clocks_stop,via[x].t2_e); }


/* Profile 5/10 specs

Model A9M0005  5 Megabyte (Discontinued)
      A9M0100 10 Megabyte (Discontinued)

 I. Technical Specifications

     1. Data Storage Characteristics:

                                    A9M0100   A9M0005

        Data Capacity (formatted)
                     in megabytes:     10         5
                    Data Surfaces:      4         4
                Heads per Surface:      1         1
           Track Spacing per inch:    345       254
               Tracks per Surface:    306       152
                Sectors per Track:     16        16
              Sectors per Surface:   4896      2432
                       Block Size
                         in bytes:    512       512
         5.25" Floppy Equivalence:     70        35

The pinouts for the ProFile card are as follows:

         1   PHI            13   XD7
         2   GND            14   GND
         3   TRw            15   PSTRB (low = true)
         4   GND            16   BSY/INT (low = true)
         5   XD0            17   CMD (low = true)
         6   XD1            18   RPARITY (low = true)
         7   (not used)     19   GND
         8   XD2            20   GND
         9   GND            21   CRES (low = true)
        10   GND            22   XD3
        11   XD5            23   XD4
        12   XD6            24   GND
                            25   CDET (low = true)

 The cable to the ProFile is pin-to-pin straight through.
*/

// for the benefit of cops.c
void set_crdy_line(void) { via[1].via[IRB] |=64; DEBUG_LOG(0,"IRB=%02x",via[1].via[IRB]);}
void clr_crdy_line(void) { via[1].via[IRB] &=(255-64); DEBUG_LOG(0,"IRB=%02x",via[1].via[IRB]);}
int  is_crdy_line(void)  { return via[1].via[IRB] & 64; }

void set_kb_data_ready(void) {if (via[1].via[IER] &2) via[1].via[IFR]|=2;
                             if (cops_event<0) SET_COPS_NEXT_EVENT(0);}


static int crdy_toggle=0;

/////////////////////////////////////////////////////////////////////////////////////////////
// note these are identical to the ones in via6522 - they're static inline
// for speed, but remember to copy them here.  Could turn them into macros, but...

// pass it the via[?].t?_e, get back the timer value (used to read t1/t2)
inline static XTIMER get_via_timer_left_from_te(XTIMER t_e)
{
  //int32 diff=(t_e-cpu68k_clocks)/via_clock_diff;
    XTIMER diff=CPUCLK_TO_VIACLK( (t_e-cpu68k_clocks) );
    DEBUG_LOG(0,"t_e-clocks:%llx-%llx = %llx adjusted_diff:%llx",  t_e,cpu68k_clocks,  t_e-cpu68k_clocks, diff);
    return (diff>0 && t_e>0) ? diff : 0;
}

inline static XTIMER get_via_timer_left_or_passed_from_te(XTIMER t_e, XTIMER timersetval)
{
  //int32 diff=(t_e-cpu68k_clocks)/via_clock_diff;
    XTIMER diff=CPUCLK_TO_VIACLK( (t_e-cpu68k_clocks) );
    XTIMER passed=CPUCLK_TO_VIACLK( timersetval-cpu68k_clocks );

    DEBUG_LOG(0,"t_e-clocks:%ld - %llx = %llx adjusted_diff:%llx",  t_e,cpu68k_clocks,  t_e-cpu68k_clocks, diff);
    if (diff>0) return diff;
    if (passed<0) return passed;
    return 0;
}


// pass it the value that was set into T1 or T2, get back the CPU clock at
// which the VIA will expire to set into via[?].t?_e
//#define VIACLK_TO_CPUCLK(X) (via_clock_diff==2 ? ((X)*LISA2ECLKFACTOR) :((X)*LISA1ECLKFACTOR))
//#define CPUCLK_TO_VIACLK(X) (via_clock_diff==2 ? ((X)/LISA2ECLKFACTOR) :((X)/LISA1ECLKFACTOR))


inline static XTIMER get_via_te_from_timer(uint16 timer)
{
    XTIMER x=cpu68k_clocks+VIACLK_TO_CPUCLK(timer);

    if (!timer) return -1;

    #ifndef USE64BITTIMER
    if (cpu68k_clocks+x>(XTIMER)(HALF_CLK))   {  prevent_clk_overflow_now();  }
    #endif

    //return cpu68k_clocks+(timer*via_clock_diff);}
    return x;
}
/////////////////////////////////////////////////////////////////////////////////////////////

// weird for some reason GCC 4.0.x complains when this is used later without a proto



// this is likely junk now.
int via_run(viatype *V)
{
	int8 shift=0, doshift=0, outputbit=0, inputbit=0;
    uint16 timer;

//       7  6  5  4  3  2  1  0
//     128 64 32 16  8  4  2  1
//  bits 432=ACR shift register control bits  16+8+4=28
	if (!V) return 0;
	if (!V->active) return 0;               // don't waste time on disabled vias.
	shift=(V->via[ACR] & 28)>>2;

    // high bit of shift is input or output mode.
    // In Lisa shift under ext clock is disabled since CB1 is NC.
    // so, shift=0, shift=3, shift=7 - no rotations done at all


/*
Shift Reg Modes
0 disabled
1 in Under T2
2 in under (|)2
3 in under ext clock
4 out under T2 free running rate
5 out under T2 control
6 out under (|)2 clock
7 out under ext clock
*/

 // T1 timer

    timer=(V->via[T1CH]<<8) | V->via[T1CL];

    if(timer)                // is there anything in the latches if so, the timer's on.
     {
          timer--; V->via[T1CH]=timer>>8; V->via[T1CL]=timer & 0xff;


          if (!timer)       // did the timer go to zero?
               {            // Are IRQ's enabled for T1?
                   if (V->via[IER]&64)
                   {   V->via[IFR] |= (64+128);
                       DEBUG_LOG(0,"T1 Timer Via#%d IRQ:%d queued.",V->vianum,V->irqnum);
                       IRQRingBufferAdd(V->irqnum,0);
                   }
                           // Will the timer reload?  Does PB7 need to be set?
                   switch ( V->via[ACR] & 192 )
                   {
                       case 128: V->via[IRB]|=128; break;     // timed interrupt each time T1 loaded, PB7 one shot mode out (PB7 goes high on fire)
                       case 192: V->via[IRB]^=128; // fall through  // continous interupts PB7 enabled (square wave)
                       case  64: V->via[T1CL]=V->via[T1LL];  // continous interrupts PB7 disabled -- reload timer
                                 V->via[T1CH]=V->via[T1LH];
                                 timer=(V->via[T1CH]<<8) | V->via[T1CL];
                                 DEBUG_LOG(0,"VIA:%d T1 running went to 0, reloaded with:%04x\n",V->vianum,timer); fflush(buglog);

                                 break;
                   }
               } else DEBUG_LOG(0,"VIA:%d T1 running:%04x\n",V->vianum,timer);
           }

 // T2 timer

    // Are we in PB6 countdown mode? If yes and no signal on PB:6, don't count down, otherwise, have fun.
    if (!(V->via[ACR] & 32) && !(V->via[IRB] & 64))
    {

      timer=(V->via[T2CH]<<8) | V->via[T2CL];


      if (timer||shift==-2)                         // if there's anything in the counter or in continous mode, allow it to decrease
            {
               timer--; V->via[T2CH]=timer>>8; V->via[T2CL]=timer & 0xff;
               if (!timer)                   // decrement the high counter
               {                                       // if both are zero, do something:
                   if (shift==4)
                   {
                       doshift=1;
                       V->via[T2CL]=V->via[T2LL]; V->via[T2CH]=V->via[T2LH];
                       timer=(V->via[T2CH]<<8) | V->via[T2CL];
                       DEBUG_LOG(0,"VIA:%d T2 running, reloaded with:%04x\n",V->vianum,timer); fflush(buglog);
                   }  // free running, reload timer from latches

                   // Interrupt the CPU if the flag is set.
                   if (V->via[IER]&32)
                   {
                       V->via[IFR] |= (32+128);            //  Set the IRQ flag for the VIA
                       DEBUG_LOG(0,"T2 Timer VIA#%d IRQ:%d queued",V->vianum,V->irqnum);
                       DEBUG_LOG(0,"T2 Timer VIA#%d IRQ:%d queued",V->vianum,V->irqnum);
                       IRQRingBufferAdd(V->irqnum,0);   // fire interrupt
                   }
               }
            }
            if (timer) DEBUG_LOG(0,"VIA:%d T2 running:%04x\n",V->vianum,timer); fflush(buglog);
    }


	if (doshift)
	{
		/*
		switch (shift)
		{
			case 1:
			case 2:
			case 3: outputbit=V->cb2 ? 1:0;	break;

			case 4: //V->cb2=inputbit=outputbit=(V->via[SHIFTREG] & 0x80) ? 1:0; break;
			case 5: //V->cb2=inputbit=outputbit=(V->via[SHIFTREG] & 0x80) ? 1:0; break;

			case 6: //V->cb2=inputbit=outputbit=(V->via[SHIFTREG] & 0x80) ? 1:0; break;

			case 7: V->cb2=inputbit=outputbit=(V->via[SHIFTREG] & 0x80) ? 1:0; break;
		}
		*/

        DEBUG_LOG(0,"Shift Register running:%02x\n",V->via[SHIFTREG]);


		if (shift>3) //hacktimized version of above
			V->cb2=inputbit=outputbit=(V->via[SHIFTREG] & 0x80) ? 1:0;
		else
			outputbit=V->cb2 ? 1:0;


        V->via[SHIFTREG]=(( (V->via[SHIFTREG]<<1) & 0xff) | (inputbit?1:0)); // do the shift operation

		V->srcount++;
		if (V->srcount==9)
		{
			if (shift==4) V->srcount=0; // free run;
			if (shift==1 && V->via[IER] & 0x04)
			{
				V->via[IFR] |= (32+128); 			//  Set the IRQ flag for the VIA
                DEBUG_LOG(0,"Shift Register VIA#:%d IRQ:%d",V->vianum,V->irqnum);
                IRQRingBufferAdd(V->irqnum,0);   // fire interrupt
			}
		}
	}
	return outputbit;
}


/*  ********* N O T E ******************************************************************
 * Need to implement via1_irb/via1_orv, etc...
 ***************************************************************************************
 *  Might have to do some DDRA DDRB ORA ORB handshaking that is when a write happens
 *  don't call any functions *IF* DDRx is 0... that way when DDRx gets set, the write
 *  will actually happen.....    hopefully I'll read this if I have problems....
 *
 *  done 980512
 *
 *
 * CA1, CA2, CB1, CB2 are 1 bit signals in/out of the VIA.  Timer can be set to count
 * pulses on PB6.  IRQ's can be triggered by CA1, CA2, CB1, CB2, or they can be used
 * as handshakes.  PB7 can be the timer output. Only Timer2 can be used to count pulses on PB6.
 * CB2 can be used as input into the SR (Shift reg)
 *
 *
 ***************************************************************************************


The parallel port is controlled by a 6522 VIA.  Ther is a direct correspondance betwn
the hardware lines on the physical connector and the assigned line
within the 6522's 2 byte ports.

 via1 and via2 handlers
 note that via1 (parallel via) sits on 8 byte boundaries
 so that MOVE.L's can be done to move lots of data at once
 to the port.

 In this via, PB is used as control, PA as data xfer:

 PB2 - DEN - disk enable, when low enabled, high=disabled.
 PB3 - RW  - read=high, low=write.
 PB4 - CMD - Command
 PB5 - OCD - When DEN is low, OCD bit returns state of disk interface -- actually this is PB0!!!
             line.
 PB6 - RDP - Read Parity permits program to read parity/ flip flop after
             data completion.  if high, there was an error in the xfer.
 PB7 - BRC-  (was baud rate control on old lisa, this has changed!)
 CB1 ------- unused on old lisa
 CB2 ------- disk interface busy signal high when disk controller busy.




PA0-PA7 --DD0-DD7 on Parallel Port
CA2  Control Line 2       -- Processor Strobe
CA1  Busy                 -- Busy
PB0  Open Cable Detect
PB1  Busy
PB2  disk enable
PB3  Read/Write
PB4  Command
PB5  Diagnostic Parity

PB7  Reset Profile

CB2  Control Line 2 - Interface Parity

(PB5) Keyboard B port 5   Pairty Reset
(PB7) Keyboard B Port 7   Controller Reset.

(Note last 3 are connected to the keyboard 6522)

The check line is encoded by the keyboard interface and roduces an independent
interrupt and keycode D000(binary) 0101 (binary) where D=1 on rising edge, 0
on falling edge.

Note that some of the bits on this 6522 are used for signals other than the
parallel port.  Also note that 2 bits for the parallel port are controlled via
the keyboard 6522.

For VIA2:

If CA1 is in pulse handshake mode and the DEN bit is low, the CA1 line pulses to
transfer data to/from the parallel port each time that data is read or written
to the A port.  CA1 is fed directly to CA2 to allow latch mode to be used on the
A port while data is being read.

The CR/ signal is generatedd by manipulation of the B port on the keyboard interface


Keyboard/Mouse Control

Keyboard and mouse control are performed by a dedicated slave processor known as COPS..
Servers Keyboard, mouse, real time clock, software power off.

*/




/*
Notes:

CA1 and CB1 can generate interrupts.

DDRA/DDRB: When a bit is 1, it's an output on the port, 0=input on the port.
Reading a corresponding 1 bit: returns what's being output.  Writing on port
sets the output bits internally, but they don't show up on the port until
DDRB are set to ones.

When DDRB=0 with input latching disabled, reads port data directly.  If input
latching is enabled, input is latched to last CB1 data, not actual port
data. (i.e. data is locked at what it was when last CB1 fired off.)

PCP Register:

bit0: 0=negative active edge, 1=positive active edge.
bits3,2,1:
321:
000-input negative active edge
001-independant interrupt input neg edge
010-input postive active edge
011-independant interrupt input postive edge
100-handshake output
101-pulse output
110-low output
111-high output

Timer T1 consists of two 8 bit latches and a 16 bit counter.  After loading,
the counter decrements at the (|)2 rate.  Upon reaching 0, an interrupt flag
will be set and IRQ will go low if the interrupt is enabled.  The timer will then
disable any further interrupts, or will automatically transfer the contents of
the latches into the counter and continue to decrement.  in addition the
timer may be programmed to invert the output signal on each count0.  each of
these modes is discussed separatly below.

Register 4- Timer 1 Low Order Counter
	Write-8 bits loaded into T1 low order latches.  contents are transfered
	into low order counter at the time the high order counter is loaded.
	Read-8 bits from T1 low order counter transfered. in addition T1 flag is reset
	(interrupt bit 6)

Register 5- Timer 1 high order counter
	Write -8 bits loaded into T1 high order latches. T1  Interrupt cleared.
	Read -8 bits from T1 high order counter read.

Register 6-Tiner 1 low order latches
	Write -8 bits loaded into T1 low order latches.  Same as to reg 4
	Read  -8 bits from T1 low order latches transfered to CPU.  Does not
	cause reset of T1 IRQ flags.
Register 7- Tiner 1 high order latches
	Write -8 bits loaded into T1 high order latches. unlike reg4 op, no latch
	to counter transfers take place.
	Read -8 bits from T1 high order latches transfered to CPU.

Reigister 11-Aux Control Register

Bit 0 = PA latch enable
Bit 1 = PB latch enable
Bits: SR control:
432:
000 disabled
001 shift in under control of T2
010 shift in under cointrol of (|)2
011 shift in under control of external clock.
100 shift out free running at T2 rate
101 shift out under control of T2
110 shift out under control of (|)2
111 shift out under control of external clock.

Bit 5: T2 Timer Control - 0=timed interrupt 1=count down with pulses on PB6

Bit 76:

76
00-Timed interrupt each time T1 is loaded.  PB7 is disabled.
01-Continous interrupts. PB7 is disabled.
10-Timed interrupt each time T1 is loaded. PB7 in one shot mode.
11-Continous interrupts - Square wave output on PB7.

One shot mode:
With ACR7=1 a write T1CH operation causes PB7 to go low.  When
timer 1 times out, PB7 returns high.  Single pulse.

Writing to high order latch has no effect on T1 timer, however.
low order latch must contain proper data before initiating the
count down with a write T1CH.  When the CPU writes to the high order
counter the T1 interrupt flag will be cleared, the contents
of the low ordered counter transfered to the low order latches, and
timer decs at system clock rate.

If PB7 output is enabled, signal will go low on the phase two following
the write operation.  When counter=0, the T1 irq flag wil be set, and IRQ pin
will be enaboed and PB7 goes back high.  At this time the counter will continue
to dec at system clock rate.  This allows the proc to read the counter and determine
the time since the interrupt.  However T1 irq flag cannt be set again unless cleared.


Free Run:

Produces a square wave on PB7 whose freq is not affected by CPU.  In the free
running mode th4e IRQ flag is set and PB7 is inverted each time the counter
reaches zero, however instead of continuing to dec from zero after a time out, the
timer automatically transfers the contents of the latch into the counter (16 bits)
and continues.  Irq flag can be cleared by writing T1CH or reading T1CL or writing
into the flag.  not necessary to rewrite the timer to enable setting the irq flag
on the next time out.


Timer 2 Operation:

Timer 2 operates as an interval timer (in one shot mode only.) or as a counter
for counting negative signals on input of PB6.  A single control bit is provided
in ACR to select between modes.  This timer is comprised of a write only low order
latch (t2ll) and a read only low order conter, and a read/write high order counter.
The counter registers act as a 16 bit counter which decrements at (|)2 rate.

t2low order counter
reg8	-write 8bits loaded into T2 low order latches.
	-read 8bits from t2 low order counter to CPU. IRQ T2 reset.
t2high order counter
reg9	-write 8 bits loaded into T2 high order counter, low order latches transfered
	 to low order counter, T2 irq flag reset.
	-read 8 bits from T2 high order counter to CPU.

T2 Pulse Counting Mode:

In PCM t2 serves to count a predetermined number of negative pulses to PB6.  this is
accomplished by 1st loading the number into T2, writing into T2c clears irq flag for
t2 and allows the counter to dec each time a pulse is applied to pb6.  the irq
flag will be set when t2 reaches zero, counter will continue to decrement with each
pulse on PB6, however it is necessary to rewrite T2CH to allow the IRQ flag to set on
subsequent down counting operations.

Shift Reg operations:

The SR performs serial transfers into and out of the CB2 pin under control of an internal
modulo 8 counter.  shift pulses can be applied to the cb1 pin from an external source or with the
proper mode selection, shift pulses generally will appear on the CB1 pin for controlling
external devices.

Control bits which select the various shift register modes are in ACR.

SR: When shifting out bit 7 is 1st out and simultaneously reloaded in bit 0.
    When shifting in bits, intiallyu enter at 0 and shifted toward 7 (*2)

    out <-- 7 6 5 4 3 2 1 0 <-- in
     \________________________/|

432:
000 disabled
001 shift in under control of T2
010 shift in under cointrol of (|)2
011 shift in under control of external clock.
100 shift out free running at T2 rate
101 shift out under control of T2
110 shift out under control of (|)2
111 shift out under control of external clock.
CB1 acts as clock, CB2 acts as shift data.

Interrupt operation:

Associated with each irq is an interrupt enable bit.
This can be set or cleared by the CPU to enable
interrupting. Bit 7 of this register will be read as
a logic 1 when an interrupt exists within the chip.
this allows very convenient polling of several devices
within a system to locate the source of the irq.

Interrupt enable register (reg 14)
0-CA2
1-CA1
2-SR
3-CB2
4-CB1
5-T2
6-T1
7-Set/Clear
0=disable irq, 1=enable irq.
IF bit 7=0 then each 1 in bits0-6 disables the corresonding irq.
if bit 7=1 then each 1 in bits0-6 enables the corresponding irq.
If a read of this register is done, but 7 will be 0 and other bits reflect
their enable/disable state.

Interrupt Flag Register (reg 13)
can be read by CPUm writing a 1 bit to these will clear them.
IRQ=ifr6*ier6+ifr5*ier5+...ifr0*ier0.

bit  set by          cleared by
0---CA2 active edge  read or write reg 1
1---CA1 active edge  read or write reg 1
2---SR  complete 8 shifts | read or write SR
3---CB2 active       read or write ORB*
4---CB1 active       read/write ORB
5---T2  time out t2  read t2low or write t2high
6---T1  time out t1  read t1l or write t1high
7---IRQ any enabled  clear all interrupts
* if CA2/CB2 control in the PCR is selected as independant
interrupt input, then reading or writing output register ora/orb will not
clear the flag but. instead the bit must be cleared by writing into the ifr.


*/


// in the Lisa's case we have two VIA controllers, so we'll need two sets of
// registers.


#define via1  (via[0])
#define via2  (via[1])
#define via0l (via[2])
#define via0h (via[3])
#define via1l (via[4])
#define via1h (via[5])
#define via2l (via[6])
#define via2h (via[7])


//viatype via1, via2,                     // built in VIA's
//
//        via0l, via0h,                   // slot 0 VIA's.
//        via1l, via1h,                   // slot 1 VIA's.
//        via2l, via2h;                   // slot 2 VIA's.


/*
* The KEYBOARD interface.                                                              *
*                                                                                      *
*The keyboard interfaces uses to Control Oriented Processor System (COPS) Microprocesrs*
* The COPS on the keyboard communicates key-up/key-down info to the 68K over a bi-     *
* directional serial interface.  The other COPS is on the I/O board.  It connects      *
* the bi-dir kb signal to the 68k by way of an 8 bit parallel port implemented with a  *
* 6522 VIA.                                                                            *
*                                                                                      *
* Since the same circuitry which is connected to the power-on push button, the power   *
* supply ON signal, and the power fail signal, also supplies the clock/calendar func   *
* it is possible for software to cause the system to turn itself on and off.           *
*                                                                                      *
* The 6522 has two 8 bit parallel I/O ports (PA0-PA7) and (PB0-PB7).  The control      *
* lines for these ports are CA1, CA2, CB1, and CB2.  The bit assignment is as follows: *
*                                                                                      *
* Lisa Name: CD?: Synertek name: PA?.                                                  *
*                                                                                      *
* CD0-7 - databus for talking witht he COPS                                            *
* CA1 must be programmed as an input that latches the COPS data in PA port             *
* CA2 must be programmed to handshake with the COPS to indicate it has been latched.   *
*                                                                                      *
* 6522 Peripheral B Port   (64)                                                       *
*                                                                                      *
* Lisa Name: CR/ CRDY PR/ FDIR VC2 VC1 VC0 ENC                                         *
* 6522 Name: PB7 PB6  PB5 PB4  PB3 PB2 PB1 PB0                                         *
*                                                                                      *
* ENC: Controls the CVSD Encode/Decode Line.  When ENC is high the CVSD circuit is in  *
*      encode mode.                                                                    *
*                                                                                      *
* VC0-VC2 These bits control the speaker volume.  When all thre bits are low, the      *
*         speaker is at its lowest volume.  As the three bit # formed by VC0-2 increses*
*         the speaker volume increases.                                                *
*                                                                                      *
* FDIR    Floppy Disk Interrupt Request.  Before attempting to read from the memory    *
*         shared by the 68k and disk controller, it is necessary to insure that the    *
*         floppy disk controller is the source of the level 1 interrupt.  If it is     *
*         not, the attempted memory access would disturb the disk operation in progress*
*         The FDIR input allows the disk interrupt line to be sensed to check this     *
*         condition.  If FDIR is 1, the controller is the source of the interrupt so   *
*         the 68k can safely read the memory. (set FDIR, then gen Level 1 IRQ when     *
*         disk read succedes.)                                                         *
*                                                                                      *
* PR/     (low true) PR/ resets the parity latch in the hard disk controller it should *
*         be pulsed low before each disk data transfer so that any parity errors which *
*         are detected durring the transfer can be passed on to the driver.  If CR/    *
*         (PB7) is high, then PR/ is an input from the parallel port.  (lock this to   *
*         1???                                                                         *
*                                                                                      *
* CRDY    COPS ready.  This signal undergoes a high to low transition when the COPS is *
*         ready to accept a command.  (see timing diagram on p 28).  There is no       *
*         handshake on entering a command.                                             *
*                                                                                      *
*         -----________----- CRDY             CRDY Width: min: 16us, MAX: 20us         *
*         xxxxxxxxx CD0-CD7 Data is valid.    TSetup(++):     -8us,       15us         *
*              ++++****                       THold (**):     20us,       50us         *
*                                                                                      *
*         Data is valid for TSetup+THold. time.                                        *
*                                                                                      *
* CR/     Controller Reset.  When CR/ is low, you can reset the Pippin Controller      *
*         connected to the hard disk port.                                             *
*                                                                                      *
* CB1     CB1 is used to clock data transfers between the 6522 shift register and      *
*         CVSD circuit under the control of T2.                                        *
*                                                                                      *
* CB2     CB2 is a data I/O pin between the 6522 shift register and the CVSD circuit.  *
*                                                                                      *
* Register    Reg #       Reg Function                    Address                      *
*                                                                                      *
* ORB/IRB      0          Output/Input Register B         $00D181                      *
* ORA/IRA      1          Output/Input Register A         $00D183                      *
* DDRB         2          Data Direction Register B       $00D185                      *
* DDRA         3          Data Direction Register A       $00D187                      *
* T1C-L        4          T1 Low Order Latches/Counter    $00D189                      *
* T1C-H        5          T1 High Order Counter           $00D18B                      *
* T1L-L        6          T1 Low Order Latches            $00D18D                      *
* T1L-H        7          T1 High Order Latches           $00D18F                      *
* T2C-L        8          T2 Low Order Latches/Counter    $00D191                      *
* T2C-H        9          T2 High Order Counter           $00D193                      *
* SR          10          Shift Register                  $00D195                      *
* ACR         11          Auxiliary Control Register      $00D197                      *
* PCR         12          Peripheral Control Register     $00D199                      *
* IFR         13          Interrupt Flag Register         $00D19B                      *
* IER         14          Interrupt Enable Register       $00D19D                      *
* ORA/IRA     15          Same as reg 1 but w/o handshake $00D19F                      *
*                                                                                      *
* Register 15 should be used when transferring commands to the COPS.  All the 6522     *
* register addresses are in the I/O address space. The T1 timer in the 6522 is         *
* reserved for use as an interval timer by the operating system ***.  See the 6522     *
* data sheet in the Synertek MOS data catalog.                                         *
*                                                                                      *
*                                                                                      *
* The CD bus (bits CD0 to CD7) above can send commands to the COPS:                    *
*                                                                                      *
* CD7-CD0     Function:                                                                *
* ----------------------------------------------------------------------------------   *
* 0000 0000    Turn I/O port on                                                        *
* 0000 0001    Turn I/O port off                                                       *
* 0000 0010    Read clock data                                                         *
* 0001 nnnn    Write nnnn to the clock.                                                *
* 0010 spmm    Set clock modes (see clock)                                             *
* 0011 nnnn    Write nnnn to the low  indicator bits in keyboard.                      *
* 0100 nnnn    Write nnnn to the high indicator bits in keyboard.                      *
* 0101 nnnn    Set High nibble of NMI character to nnnn                                *
* 0110 nnnn    Set Low nibble of NMI character to nnnn                                 *
* 1xxx xxxx    NOP                                                                     *
*                                                                                      *
* If the 6522 is not programmed as an output when the CRDY line makes a high to low    *
* transition (thereby indicating that the COPS is ready to accept a command), the pull *
* up on the CD bus prevents a spurious command from being entered (ignore)             *
*                                                                                      *
* The pin description given above indicates that the CD bus (the Peripheral A port)    *
* should be setup to handshake and to latch data.                                      *
*                                                                                      *
* If the 6522 is setup correctly when the I/O board COPS has data for the 68k, it will *
* handshake with the handshake lines and generate an interrupt.                        *
*                                                                                      *
* The indicator bits can be used to control 8 LEDs.  If for example those LEDs are     *
* installed on the keyboard, they can be used to emulate a VT100 terminal.             *
*                                                                                      *
* RESET CODES                                                                          *
*                                                                                      *
* In addition to the Key Up and Key Down information, the keyboard COPS produces       *
* severl two byte reset codes.  These two byte reset codes consist of a reset char     *
* ($8-) and a code #:                                                                  *
*                                                                                      *
* FF - Keyboard COPS failure detected.                                                 *
* FE - I/O board COPS failure detected.                                                *
* FD - Keyboard unplugged.  The reset code of the keyboard ID will follow when plugged *
*      back in.                                                                        *
* FC - Clock timer Interrupt                                                           *
* FB - Soft Power Switch pressed (do a soft-off.)                                      *
* Ey - Clock data follows (five bytes, y is the year.):                                *
*      $80 $Ey dd dh hm ms st - dd day, hh hour, mm=minute, ss second t=1/10 of second *
*                                                                                      *
* F0-FA reserved for future use.                                                       *
*                                                                                      *
* 0-DF keyboard ID #.  The current only keyboard is 01.  The keyboard ID reset code    *
* is produced whenever the keyboard COPS is reset.  This happ[ens on poweron and when  *
* keyboard is plugged in.                                                              *
*                                                                                      *
* The KEYBOARD                                                                         *
*                                                                                      *
*The keyboard connects through the jack on the lower right front of the Lisa.  It's    *
* 80 keys are fully programmable.                                                      *
*                                                                                      *
*The keyboard contains a microprocessor which scans the keys and communicates the      *
*occurance of a key depression or release to the 68000.  The keyboard is a true N-key  *
*rollover design.  An arbitrary number of keys can be depressed without causing        *
*phantom key problems.  It is the responsability of the 68000 side of the interface to *
*interpret key up and key down codes to properly handle functions such as shift and    *
*auto-repeat.  Any key can be programmed to generate an NMI (non-maskable interrupt.)  *
*                                                                                      *
*The keyboards microprocessor contains an 8 byte FIFO that buffers keyboard data if the*
*68000 does not collect it fast enough.  Normally, this FIFO keeps keycodes from being *
*lost, but if the keycodes aren't read for a long time, the buffer will eventually     *
*overflow and keycodes will be lost.                                                   *
*                                                                                      *
*KEYCODES.                                                                             *
*                                                                                      *
* Seven bits of the keycode byte identify the key which moved.  The other bit indicates*
* the direction.  drrr nnnn.  If d=0 a key up transition occured.  If d=1 then a key   *
* down transition has occured.                                                         *
*                                                                                      *
* (See table on page 33)                                                               *
*                                                                                      *
*                                                                                      *
* THE MOUSE                                                                            *
*                                                                                      *
* The mouse is an input device with motion sensors and one or more buttons.  It sends  *
*  movement and button information to the computer through the keyboard 6522.  This    *
* info os usually used to provide a fast and convenient pointing and drawing mechanism *
* by tracking the mouse movement in some direct manner with the cursor on screen.      *
*                                                                                      *
* ....                                                                                 *
*                                                                                      *
* MOUSE COMMANDS:                                                                      *
*                                                                                      *
* Mouse commands are sent to the 6522 Peripheral port A data bus PA0-PA7 in the format *
* 0111 ennn                                                                            *
*                                                                                      *
* If e is set, mouse interrupts are enabled.  The nnn bits set the time interval that  *
* will separate mouse interrupts.                                                      *
*                                                                                      *
* Once mouse interrupts are enabled and the time interval has been set, the COPS       *
* interrupts the 68k whenever the mouse moves.  The time between interrupts is about   *
* 4ms times the number given in the nnn bits.                                          *
*                                                                                      *
* For example the command $7C (01111100) enables the mouse to interrupt 16 ms (100=    *
* 4*4ms) after the mouse begins to move.  If the mouse continues to move, interrupts   *
* are generated every 16ms.                                                            *
*                                                                                      *
* MOUSE DATA                                                                           *
*                                                                                      *
* Mouse generated data is sent to the 68000 in three bytes:                            *
*                                                                                      *
* 00 (mouse data follows) dx   dy.  The dx and dy values which are in the range of     *
* -128 to + 127 are reset every time the 68000 reads them.  While the mouse is moving  *
* and mouse interupts are enabled, a new dx and dy value can be read every nnn*4ms     *
* If the 68k doesn't respond to the mouse irq and read the mouse data, the dx and dy   *
* values are updated and collected in the interface's 8 byte FIFO buffer.  If the      *
* mouse is ignored long enough, the buffer will overflow and mouse data will become    *
* invalid.                                                                             *
*                                                                                      *
*The mouse button is returned as keycode d000 0110.  If the d bit is 1, the button     *
*has been pressed.  If the d bit is 0, the button has been released.  The d bit in     *
*keycode d000 0101 is 1 if the mouse is plugged in, and 0 if not. The third mouse      *
*keycode (d0000111) is currently unused.                                               *
*                                                                                      *
* The Clock/Calendar Circuit.                                                          *
*                                                                                      *
* The clock calendar is a part of the keyboard encoder circuitry.  The clock resolves  *
* to 1/10ths of a second and needs to be reset only once every 16 years.  In addition  *
* there is an alarm clock that can be programmed to generate an interrupt at any time  *
* upto $FFFFF seconds (12.14 days 291.27 hours.) This interrupt can be programmed      *
* to generate a system power up.                                                       *
*                                                                                      *
* The 6522 Peripheral port A databus (PA0-PA7) is used to communicate with the clock.  *
*                                                                                      *
* PA7 PA0       function                                                               *
* -----------------------------------------------                                      *
* 0000 0010     Read Clock Data.                                                       *
* 0001 nnnn     Write nnnn to clock                                                    *
* 0010 spmm     Set Clock Modes                                                        *
*                                                                                      *
* Clock Modes:                                                                         *
* ------------------------------------------------                                     *
* mm    function                                                                       *
* ------------------------------------------------                                     *
* 00    clock/timer disable                                                            *
* 01    timer disable                                                                  *
* 10    Timer underflow generates interrupt                                            *
* 11    Timer underflow turns system on if it is off and gens interrupt                *
*                                                                                      *
* If the p bit above is zero the system is turned off, if it's one and the system is   *
* off, the system is turned back on.                                                   *
*                                                                                      *
* (We can probably ignore this stuff.)                                                 *
*                                                                                      *
*                                                                                      *
* Setting the Clock                                                                    *
*                                                                                      *
* The s bit, if set, enables the clock set mode, and the 16 nibbles of time data can   *
* be entered one digit (nibble) at a time.  Only as man nibbles as desired ned to be   *
* entered durring the time setting operation.  Once the time has been set, the s bit   *
* is cleared and the operation terminated.  The clock and timer must be stopped while  *
* the time is being set.  To do this, set the clock mode to clock/timer disable (00)   *
* durring the operation, then reset it to timer disable ($01) when done.  The clock    *
* can be left running while setting the alarm, but the timer must be disabled.         *
*                                                                                      *
* The order in which the time information is entered durring the time set operation is *
* 11223 3 445 56 67 78 8                                                               *
* aaaaa y ddd hh mm ss t (8 bytes total in nibbles)                                    *
*                                                                                      *
* aaaaa alarm nibbles ($0 $FFFFF) (0-1,048,575)                                        *
* y     year (0-15)                                                                    *
* ddd   day  (1-366)                                                                   *
* hh    hour (0-23)                                                                    *
* mm    minute (0-59)                                                                  *
* ss    second (0-59)                                                                  *
* t     tenth of second (0-9)                                                          *
*                                                                                      *
* The alarm counts down one count per second and generates an interrupt upon the       *
* $00000 -> $FFFFF transition. Since the five alarm nibbles are entered first, the     *
* alarm can be set without disturbing the clock.  All the nibbles are maintained in    *
* decimal format except the alarm and year nibbles which are kept in decimal form to   *
* reduce the amount of code required to handle them.                                   *
*                                                                                      *
* Alarm corresponds to: 1,048,575 sec, 17,476.25 mins, 291.27 hrs, 12.14 days,1.73weeks*
*                                                                                      *
*                                                                                      */

uint8 via1_irb(uint8 reg);
void via1_orb(uint8 data);

uint8 via2_ira(uint8 regnum);
uint8 via2_irb(void);
void  via2_ora(uint8 data, uint8 regnum);
void  via2_orb(uint8 data);



// VIA Wrapper around ProFile loop to handle BSY (CA1) IRQ's -- if they're enabled that is.
void VIAProfileLoop(int vianum, ProFileType *P, int event)
{
int BSY=P->BSYLine;

//    if (via[2].ProFile->DENLine!=0) return;

    ProfileLoop(P,event);

    // IF BSY has changed, and CA1 IRQ's are enabled, then, see if we need to send an IRQ based on polarity in PCR CA1 bit
    if (P->BSYLine !=BSY)
    {
      //- not sure which is right. 1=positive edge, 0=negative edge, I think the logical XOR
      //if (P->BSYLine!=0) && ((via[vianum].via[PCR] & 1)!=0) )   via[vianum].via[IFR] |=VIA_IRQ_BIT_CA1;

        DEBUG_LOG(0,"oldbsy:%d newbsy:%d PCR_bit0:%d   tag:profile.c",BSY,P->BSYLine,via[vianum].via[PCR]);

        if ((P->BSYLine!=0) ^  ((via[vianum].via[PCR] & 1)!=0) )
                {
                    via[vianum].via[IFR] |=VIA_IRQ_BIT_CA1;

                    DEBUG_LOG(0,"state:%d Enabled CA1(BSY) on %d->%d BSY transition pcr:%d pc24:%08x tag:profile.c",
                              P->StateMachineStep,BSY,P->BSYLine,
                              (via[vianum].via[PCR] & 1), pc24);
                }
        else

                {
                    DEBUG_LOG(0,"state:%d Didn't enable CA1(BSY) on %d->%d BSY transition pcr:%d pc24:%08x tag:profile.c",
                              P->StateMachineStep,BSY,P->BSYLine,
                              (via[vianum].via[PCR] & 1), pc24);
                }
        // too bad we don't have a ^^ operator like we do && and || - logical XOR would be nice here.

    }
}



/***********************************************************************************\
*  Functions to handle VIA2 I/O for profile drive                                   *
*                                                                                   *
\***********************************************************************************/

char *via_regname(int i)
{
switch(i)
 {
  case 0: return "I/ORB     ";
  case 1: return "I/ORA     ";
  case 2: return "DDRB      ";
  case 3: return "DDRA      ";
  case 4: return "T1CL      ";
  case 5: return "T1CH      ";
  case 6: return "T1LL      ";
  case 7: return "T1LH      ";
  case 8: return "T2CL      ";
  case 9: return "T2CH      ";
  case 10: return "SHIFTR   ";
  case 11: return "ACR      ";
  case 12: return "PCR      ";
  case 13: return "IFR      ";
  case 14: return "IER      ";
  case 15: return "I/ORANH  ";

  case 16: return "T2LL shadow";
  case 17: return "T2LH shadow";

 }
 return "Unknown via regname!";
}


void fdumpvia1(FILE *out)
{
    int i, pcr, acr;

    fflush(out);
    fprintf(out,"Current CPU clock:%llx\n",cpu68k_clocks);
    fprintf(out,"via1 (COPS Controller) active:%d\n",via[1].active);
    fprintf(out,"via1 vianum:%d\n",via[1].vianum);

    fprintf(out,"via1 irqnum:%d\n",via[1].irqnum);
    fprintf(out,"via1 srcount:%d\n",via[1].srcount);
    fprintf(out,"via1 CA1,2/CB1,2:%02x,%02x/%02x,%02x\n",via[1].ca1,via[1].ca2,via[1].cb1,via[1].cb2);
    for ( i=0; i<18; i++)
        {
            fprintf(out,"via1 reg[%d]=%02x %s\n",i,via[1].via[i],via_regname(i));

            if (i==2) fprintf(out,"PB0:%s !PB1:%s PB2:%s PB3:%s !PB4:%s PB5:%s PB6:%s PB7:%s \n",
                      via[1].via[i] & 1   ? "Out":"In",
                      via[1].via[i] & 2   ? "Out":"In",
                      via[1].via[i] & 4   ? "Out":"In",
                      via[1].via[i] & 8   ? "Out":"In",
                      via[1].via[i] & 16  ? "Out":"In",
                      via[1].via[i] & 32  ? "Out":"In",
                      via[1].via[i] & 64  ? "Out":"In",
                      via[1].via[i] & 128 ? "Out":"In");

            if (i==0) fprintf(out,"PB0:kreset:%s PB1-3:volume:%d PB4:floppy:%s PB5:parity_reset:%s PB6:cops_handshake:%s PB7:ctrl_reset:%s \n",
                      via[1].via[i] & 1   ? "On":"Off",

                      (via[1].via[i]>>1) & 7,

                      via[1].via[i] & 16  ? "On":"Off",
                      via[1].via[i] & 32  ? "On":"Off",
                      via[1].via[i] & 64  ? "On":"Off",
                      via[1].via[i] & 128 ? "On":"Off");

        fflush(out);
        }

    fprintf(out,"VIA1 IFR: (fired IRQ's): ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_CA2)          fprintf(out,"CA2 ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_CA1 )         fprintf(out,"CA1 ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_SR  )         fprintf(out,"SHIFTREG ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_CB2 )         fprintf(out,"CB2 ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_CB1 )         fprintf(out,"CB1 ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_T2  )         fprintf(out,"TIMER2 ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_T1  )         fprintf(out,"TIMER1 ");
    if (via[1].via[IFR] & VIA_IRQ_BIT_SET_CLR_ANY ) fprintf(out,"IRQON ");
    fprintf(out,"\n");
    fprintf(out,"VIA1 IER: (enabled IRQs): ");
    if (via[1].via[IER] & VIA_IRQ_BIT_CA2)          fprintf(out,"CA2 ");
    if (via[1].via[IER] & VIA_IRQ_BIT_CA1 )         fprintf(out,"CA1 ");
    if (via[1].via[IER] & VIA_IRQ_BIT_SR  )         fprintf(out,"SHIFTREG ");
    if (via[1].via[IER] & VIA_IRQ_BIT_CB2 )         fprintf(out,"CB2 ");
    if (via[1].via[IER] & VIA_IRQ_BIT_CB1 )         fprintf(out,"CB1 ");
    if (via[1].via[IER] & VIA_IRQ_BIT_T2  )         fprintf(out,"TIMER2 ");
    if (via[1].via[IER] & VIA_IRQ_BIT_T1  )         fprintf(out,"TIMER1 ");
    if (via[1].via[IER] & VIA_IRQ_BIT_SET_CLR_ANY ) fprintf(out,"SET/!CLR");
    fprintf(out,"\n");
    fprintf(out,"VIA1 Timer 1 fired %16llx times\n",via[1].t1_fired);
    fprintf(out,"VIA1 Timer 2 fired %16llx times\n",via[1].t2_fired);
    fflush(out);

    pcr=via[1].via[12];
    fprintf(out,"via1 PCR: CA1:%s\n", (pcr & 1) ? "Postive Active Edge":"Negative Active Edge");
    switch( (pcr>>1) & 7)
    {case 0: fprintf(out,"via1 PCR: CA2: 000 Input Negative Active Edge\n"); break;
     case 1: fprintf(out,"via1 PCR: CA2: 001 Independent IRQ Input Negative Edge\n"); break;
     case 2: fprintf(out,"via1 PCR: CA2: 010 Input Positive Active Edge\n"); break;
     case 3: fprintf(out,"via1 PCR: CA2: 011 Independent IRQ Input Positive Edge\n"); break;
     case 4: fprintf(out,"via1 PCR: CA2: 100 Handshake Output\n"); break;
     case 5: fprintf(out,"via1 PCR: CA2: 101 Pulse Output\n"); break;
     case 6: fprintf(out,"via1 PCR: CA2: 110 Low Output\n"); break;
     case 7: fprintf(out,"via1 PCR: CA2: 111 High Output\n"); break;
    }
    fprintf(out,"via1 PCR: CB1:%s\n", (pcr & 16) ? "Postive Active Edge":"Negative Active Edge");
    switch( (pcr>>5) & 7)
    {case 0: fprintf(out,"via1 PCR: CB2: 000 Input Negative Active Edge\n"); break;
     case 1: fprintf(out,"via1 PCR: CB2: 001 Independent IRQ Input Negative Edge\n"); break;
     case 2: fprintf(out,"via1 PCR: CB2: 010 Input Positive Active Edge\n"); break;
     case 3: fprintf(out,"via1 PCR: CB2: 011 Independent IRQ Input Positive Edge\n"); break;
     case 4: fprintf(out,"via1 PCR: CB2: 100 Handshake Output\n"); break;
     case 5: fprintf(out,"via1 PCR: CB2: 101 Pulse Output\n"); break;
     case 6: fprintf(out,"via1 PCR: CB2: 110 Low Output\n"); break;
     case 7: fprintf(out,"via1 PCR: CB2: 111 High Output\n"); break;
    }

    acr=via[1].via[11];
    fprintf(out,"via1 ACR: PA %s\n",(acr & 1) ? "latching enabled":"latching disabled");
    fprintf(out,"via1 ACR: PB %s\n",(acr & 2) ? "latching enabled":"latching disabled");
    fprintf(out,"via1 SHIFT Register Control: ");
    switch ((acr>>2) & 7)
    {
      case 0: fprintf(out,"000 Disabled\n"); break;
      case 1: fprintf(out,"001 under control of T2\n"); break;
      case 2: fprintf(out,"010 under control of phi2\n"); break;
      case 3: fprintf(out,"011 under control of ext. clock\n"); break;
      case 4: fprintf(out,"100 free running at t2 rate\n"); break;
      case 5: fprintf(out,"101 under control of t2\n"); break;
      case 6: fprintf(out,"110 under control of phi2\n"); break;
      case 7: fprintf(out,"111 under control of ext. clock\n"); break;
    }

    fprintf(out,"via1 ACR: T2 Timer Control:%s\n",(acr & 32) ? "Countdown with pulses on PB6":"Timed IRQ");

    fprintf(out,"via1 T2 cpu_68k clk expiration:%016llx cpu68k_clocks:%16llx fired %lld times\n",via[1].t2_e,cpu68k_clocks,via[1].t2_fired);
    fprintf(out,"via1 T1 cpu_68k clk expiration:%016llx cpu68k_clocks:%16llx fired %lld times\n",via[2].t1_e,cpu68k_clocks,via[1].t1_fired);


    fprintf(out,"via1 T1 Control: ");
    switch (acr>>6)
    {
      case 0: fprintf(out,"00 Timed IRQ each time T1 Loaded, PB7 Disabled\n"); break;
      case 1: fprintf(out,"01 Continous IRQ's  PB7 Disabled\n"); break;
      case 2: fprintf(out,"10 Timed IRQ each time T1 Loaded, PB7 One Shot Output\n"); break;
      case 3: fprintf(out,"11 Continous IRQ's, PB7 Square Wave Output\n"); break;
    }
    fflush(out);
}

void fdumpvia2(FILE *out)
{
    int i, pcr, acr;

    fprintf(out,"\n\nvia2 (Motherboard Parallel Port) active:%d\n",via[2].active);
    fprintf(out,"via2 vianum:%d\n",via[2].vianum);

    fprintf(out,"via2 irqnum:%d\n",via[2].irqnum);
    fprintf(out,"via2 srcount:%d\n",via[2].srcount);
    fprintf(out,"via2 CA1,2/CB1,2:%02x,%02x/%02x,%02x\n",via[2].ca1,via[2].ca2,via[2].cb1,via[2].cb2);

    for ( i=0; i<18; i++) fprintf(out,"via2 reg[%d]=%02x %s\n",i,via[2].via[i],via_regname(i));

            if (i==2) fprintf(out,"PB0:%s PB1:%s PB2:%s PB3:%s PB4:%s PB5:%s PB6:%s PB7:%s \n",
                      via[2].via[i] & 1   ? "OCD:Out":"OCD:In",
                      via[2].via[i] & 2   ? "BSY:Out":"BSY:In",
                      via[2].via[i] & 4   ? "DEN:Out":"DEN:In",
                      via[2].via[i] & 8   ? "RRW:Out":"RRW:In",
                      via[2].via[i] & 16  ? "CMD:Out":"CMD:In",
                      via[2].via[i] & 32  ? "PAR:Out":"PAR:In",
                      via[2].via[i] & 64  ? "DSK:Out":"DSK:In",
                      via[2].via[i] & 128 ? "CRS:Out":"CRS:In");

            if (i==0) fprintf(out,"PB0:OCD:%s PB1:!BSY:%s PB2:!DEN:%s PB3:drw:%s PB4:!CMD:%s PB5:!parity:%s PB6:FDIR:%s PB7:Contrast:%s \n",
                      via[2].via[i] & 1   ? "no":"connected",
                      via[2].via[i] & 2   ? "busy":"ready",
                      via[2].via[i] & 4   ? "contrast":"parallel",
                      via[2].via[i] & 8   ? "write":"read",
                      via[2].via[i] & 16  ? "no":"yes",
                      via[2].via[i] & 32  ? "ok":"error",
                      via[2].via[i] & 64  ? "1":"0",
                      via[2].via[i] & 128 ? "1":"0");

    fprintf(out,"VIA2 IFR: (fired IRQ's): ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_CA2)          fprintf(out,"CA2 ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_CA1 )         fprintf(out,"CA1 ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_SR  )         fprintf(out,"SHIFTREG ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_CB2 )         fprintf(out,"CB2 ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_CB1 )         fprintf(out,"CB1 ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_T2  )         fprintf(out,"TIMER2 ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_T1  )         fprintf(out,"TIMER1 ");
    if (via[2].via[IFR] & VIA_IRQ_BIT_SET_CLR_ANY ) fprintf(out,"IRQON ");
    fprintf(out,"\n");
    fprintf(out,"VIA2 IER: (enabled IRQs): ");
    if (via[2].via[IER] & VIA_IRQ_BIT_CA2)          fprintf(out,"CA2 ");
    if (via[2].via[IER] & VIA_IRQ_BIT_CA1 )         fprintf(out,"CA1 ");
    if (via[2].via[IER] & VIA_IRQ_BIT_SR  )         fprintf(out,"SHIFTREG ");
    if (via[2].via[IER] & VIA_IRQ_BIT_CB2 )         fprintf(out,"CB2 ");
    if (via[2].via[IER] & VIA_IRQ_BIT_CB1 )         fprintf(out,"CB1 ");
    if (via[2].via[IER] & VIA_IRQ_BIT_T2  )         fprintf(out,"TIMER2 ");
    if (via[2].via[IER] & VIA_IRQ_BIT_T1  )         fprintf(out,"TIMER1 ");
    if (via[2].via[IER] & VIA_IRQ_BIT_SET_CLR_ANY ) fprintf(out,"SET/!CLR");
    fprintf(out,"\n");
    fprintf(out,"VIA2 Timer 1 fired %lld times\n",via[2].t1_fired);
    fprintf(out,"VIA2 Timer 2 fired %lld times\n",via[2].t2_fired);


    pcr=via[2].via[12];
    fprintf(out,"via2 PCR: CA1:%s\n", (pcr & 1) ? "Postive Active Edge":"Negative Active Edge");
    switch( (pcr>>1) & 7)
    {case 0: fprintf(out,"via2 PCR: CA2: 000 Input Negative Active Edge\n"); break;
     case 1: fprintf(out,"via2 PCR: CA2: 001 Independent IRQ Input Negative Edge\n"); break;
     case 2: fprintf(out,"via2 PCR: CA2: 010 Input Positive Active Edge\n"); break;
     case 3: fprintf(out,"via2 PCR: CA2: 011 Independent IRQ Input Positive Edge\n"); break;
     case 4: fprintf(out,"via2 PCR: CA2: 100 Handshake Output\n"); break;
     case 5: fprintf(out,"via2 PCR: CA2: 101 Pulse Output\n"); break;
     case 6: fprintf(out,"via2 PCR: CA2: 110 Low Output\n"); break;
     case 7: fprintf(out,"via2 PCR: CA2: 111 High Output\n"); break;
    }
    fprintf(out,"via2 PCR: CB1:%s\n", (pcr & 16) ? "Postive Active Edge":"Negative Active Edge");
    switch( (pcr>>5) & 7)
    {case 0: fprintf(out,"via2 PCR: CB2: 000 Input Negative Active Edge\n"); break;
     case 1: fprintf(out,"via2 PCR: CB2: 001 Independent IRQ Input Negative Edge\n"); break;
     case 2: fprintf(out,"via2 PCR: CB2: 010 Input Positive Active Edge\n"); break;
     case 3: fprintf(out,"via2 PCR: CB2: 011 Independent IRQ Input Positive Edge\n"); break;
     case 4: fprintf(out,"via2 PCR: CB2: 100 Handshake Output\n"); break;
     case 5: fprintf(out,"via2 PCR: CB2: 101 Pulse Output\n"); break;
     case 6: fprintf(out,"via2 PCR: CB2: 110 Low Output\n"); break;
     case 7: fprintf(out,"via2 PCR: CB2: 111 High Output\n"); break;
    }

    acr=via[2].via[11];
    fprintf(out,"via2 ACR: PA %s\n",(acr & 1) ? "latching enabled":"latching disabled");
    fprintf(out,"via2 ACR: PB %s\n",(acr & 2) ? "latching enabled":"latching disabled");
    fprintf(out,"via2 SHIFT Register Control: ");
    switch (acr>>2)
    {
      case 0: fprintf(out,"000 Disabled\n"); break;
      case 1: fprintf(out,"001 under control of T2\n"); break;
      case 2: fprintf(out,"010 under control of phi2\n"); break;
      case 3: fprintf(out,"011 under control of ext. clock\n"); break;
      case 4: fprintf(out,"100 free running at t2 rate\n"); break;
      case 5: fprintf(out,"101 under control of t2\n"); break;
      case 6: fprintf(out,"110 under control of phi2\n"); break;
      case 7: fprintf(out,"111 under control of ext. clock\n"); break;
    }

    fprintf(out,"via2 ACR: T2 Timer Control:%s\n",(acr & 32) ? "Countdown with pulses on PB6":"Timed IRQ");
    fprintf(out,"via2 T2 cpu_68k clk expiration:%16llx cpu68k_clocks:%016llx fired %lld times\n",via[2].t2_e,cpu68k_clocks,via[2].t2_fired);
    fprintf(out,"via2 T1 cpu_68k clk expiration:%16llx cpu68k_clocks:%016llx t1_fired:%lld times\n",via[2].t1_e,cpu68k_clocks,via[2].t1_fired);

    fprintf(out,"via2 T1 Control: ");
    switch (acr>>6)
    {
      case 0: fprintf(out,"00 Timed IRQ each time T1 Loaded, PB7 Disabled\n"); break;
      case 1: fprintf(out,"01 Continous IRQ's  PB7 Disabled\n"); break;
      case 2: fprintf(out,"10 Timed IRQ each time T1 Loaded, PB7 One Shot Output\n"); break;
      case 3: fprintf(out,"11 Continous IRQ's, PB7 Square Wave Output\n"); break;
    }

}

void dumpvia(void)
{
    char filename[1024];
    FILE *out;
     return;

    //debug_log_enabled=1;
    sprintf(filename,"/log/lisaem-output-%08x.%016llx.vias.txt",pc24,cpu68k_clocks);
    out=fopen(filename,"wt");

    fdumpvia1(out);
    fdumpvia2(out);

    fclose(out);
}

void print_via_profile_state(char *s, uint8 data, viatype *V)
{
#ifdef DEBUG
  if (!debug_log_enabled) return;

  fprintf(buglog,"%s(%02x) via#:%d ProFileState#:%d widx:%d, ridx:%d,block#:%ld pb1!BSY:%d pb2!DEN:%d pb3!RRW:%d pb4!CMD:%d :: VIA:: ",s,data,
         V->vianum,
         V->ProFile->StateMachineStep,V->ProFile->indexwrite,V->ProFile->indexread,(long)V->ProFile->blocktowrite,
         V->ProFile->BSYLine,
         V->ProFile->DENLine,
         V->ProFile->RRWLine,
         V->ProFile->CMDLine);

  if (OCDLine_BIT   &  V->via[DDRB]) fprintf(buglog," !OCDLine:%02x ",    data & OCDLine_BIT);
  if (BSYLine_BIT   &  V->via[DDRB]) fprintf(buglog," !BSYLine:%02x ",    data & BSYLine_BIT);
  if (DENLine_BIT   &  V->via[DDRB]) fprintf(buglog," !DENLine:%02x ",    data & DENLine_BIT);
  if (RRWLine_BIT   &  V->via[DDRB]) fprintf(buglog," !R/RWLine:%02x ",   data & RRWLine_BIT);
  if (CMDLine_BIT   &  V->via[DDRB]) fprintf(buglog," !CMDLine :%02x ",   data & CMDLine_BIT);
  if (PARITY_BIT    &  V->via[DDRB]) fprintf(buglog," !ParityReset:%02x ",data & PARITY_BIT);
  if (DSK_DIAG_BIT  &  V->via[DDRB]) fprintf(buglog," Floppy_wait:%02x ", data & DSK_DIAG_BIT);
  if (CTRL_RES_BIT  &  V->via[DDRB]) fprintf(buglog," !ProFileReset:%02x",data & CTRL_RES_BIT);

  fprintf(buglog,"\n");
  fflush(buglog);

  //if (   (9 & via[2].via[DDRB])==9) {if ((data & OCDLine_BIT)==0) {debug_log_enabled=1; debug_on("");} }
#endif
}


void all_vias_run(void)
{

    via_run(&via[1]);
    if (copsqueuelen>0)
    {
      if ((via[1].via[IER] & VIA_IRQ_BIT_CA2))
        {
         via[1].ca2=1; crdy_toggle =1;
         DEBUG_LOG(0,"Firing Keyboard COPS IRQ AUTOVECTOR 2\n"); fflush(buglog);
         IRQRingBufferAdd(2,0);
        }
    }


    via_run(&via[2]);

    if (!via_running) return;


    if (via[3].active) via_run(&via[3]);
	if (via[4].active) via_run(&via[4]);
	if (via[5].active) via_run(&via[5]);
	if (via[6].active) via_run(&via[6]);
	if (via[7].active) via_run(&via[7]);
	if (via[8].active) via_run(&via[8]);
}

int check_contrast_set(void)
{
    //DEBUG_LOG(0,"ORA:%02x DDRA:%02x   ORB:%02x DDRB:%0x",via[2].via[ORA],via[2].via[DDRA],via[2].via[ORB],via[2].via[DDRB]);

//    if ((via[2].via[DDRB] & via[2].via[ORBB] & 0x80)==0x80 && via[2].via[DDRA]) // this is OK (DDRA used with port B!)
    if ((via[2].via[DDRB] & 0x84)==0x84 && (via[2].via[ORBB] & 0x4)==4 && via[2].via[DDRA]!=0) // this is OK (DDRA used with port B!)
	{
        contrast=via[2].via[DDRA] & via[2].via[ORAA]; videoramdirty|=9;
//        ALERT_LOG(0,"Setting Contrast:%02x",contrast);
        if ( contrast==0xff) disable_vidram(); else enable_vidram();


        contrastchange();  // force UI to adjust display

        return 1;
	}
    //#ifdef DEBUG
    //else  DEBUG_LOG(0,"NOT setting contrast.");
    //#endif

    return 0;
}



void via_ora(viatype *V, uint8 data,uint8 regnum)
{
    VIA_CLEAR_IRQ_PORT_A(V->vianum); // clear CA1/CA2 on ORA/IRA access

	if (V->vianum==1) {via1_ora(data,regnum);return; }
	if (V->vianum==2) {via2_ora(data,regnum);return; }

	if (V->ProFile)
	{
		V->via[ORA]=(V->ProFile->VIA_PA=data);
        VIAProfileLoop(V->vianum, V->ProFile,PROLOOP_EV_ORA);
		return;
	}

    if (V->ADMP) {DEBUG_LOG(0,"ADMP ORA: Sending %02x to ADMP",data);
                  ImageWriterLoop(V->ADMP,data);
                  return;}
	if (V->ora!=NULL) V->ora(V->vianum,data,regnum);

	return;
}



uint8 via_ira(viatype *V, uint8 regnum)
{

    VIA_CLEAR_IRQ_PORT_A(V->vianum);

    if (V->vianum==1) return via1_ira(regnum);
	if (V->vianum==2) return via2_ira(regnum);

	if (V->ProFile) // Is this a profile?
	{
        VIAProfileLoop(V->vianum,V->ProFile,PROLOOP_EV_IRA);
		return V->via[IRA]=V->ProFile->VIA_PA;
	}
    else if (V->ADMP) {DEBUG_LOG(0,"Polling IRA from ADMP"); return 0;} // ADMP doesn't return anything far as I know
    else if (V->ira!=NULL) return V->ira(V->vianum,regnum);

	return 0; // nothing attached, ignore.
}



void via_orb(viatype *V, uint8 data,uint8 regnum)
{
    VIA_CLEAR_IRQ_PORT_B(V->vianum);

    V->via[ORBB]=data;

	if (V->vianum==1) {via1_orb(data); return;}
	if (V->vianum==2) {via2_orb(data); return;}


	if (V->ProFile)
	{
		//	if (0x01 & V->via[DDRB]) OCD=(data & 0x01) ? 1:0;  Ignored - input only line
		//  if (0x02 & V->via[DDRB]) BSY=(data & 0x02) ? 1:0;   Ignored - input only line

        if (DENLine_BIT & V->via[DDRB]) V->ProFile->DENLine=(data & DENLine_BIT) ? 0:1;   // DEN - drive enable....
        if (RRWLine_BIT & V->via[DDRB]) V->ProFile->RRWLine=(data & RRWLine_BIT) ? 0:1;   // RRW is 1=write, 0=read from port
        if (CMDLine_BIT & V->via[DDRB]) V->ProFile->CMDLine=(data & CMDLine_BIT) ? 0:1;   // CMD line varies...

        //if (0x20 & V->via[DDRB]) V->ProFile->DENLine=(data & 0x20) ? 1:0;   // Reset Parity - Ignored
        //if (0x40 & V->via[DDRB]) V->ProFile->RRWLine=(data & 0x40) ? 1:0;   // Read/Write mode.

        if (0x80 & V->via[DDRB]) {
                                    if (data & CTRL_RES_BIT) ProfileReset(V->ProFile);
                                    else                     ProfileResetOff(V->ProFile);
                                 }  // PB7 = reset the ProFile

         if (pc24<0x00fe0000) print_via_profile_state("via_orb ", data,V);

		return;
	}
    else if (V->ADMP!=0) {
              DEBUG_LOG(0,"ADMP via_orb %s %s %s",
                    ((data & DENLine_BIT) ? "DEN=1":"DEN=0"),
                    ((data & RRWLine_BIT) ? "RRW=1":"RRW=0"),
                    ((data & CMDLine_BIT) ? "CMD=1":"CMD=0"));
              return;
             } // ADMP doesn't return anything far as I know
    else if (V->orb !=NULL) return V->orb(V->vianum,data,regnum);

	return; // nothing attached, ignore.
}


uint8 via_irb(viatype *V, uint8 regnum) // This is good
{
    uint8 retval=0;

    VIA_CLEAR_IRQ_PORT_B(V->vianum); // clear Cb1/Cb2 on ORb/IRb access

	if (V->vianum==1) return via1_irb(regnum);
	if (V->vianum==2) return via2_irb();


                                    retval |=(((V->ProFile||V->ADMP) && floppy_picked && powerfile_power)  ? 0 : OCDLine_BIT);  // ADMP/Profile attached?
    if (V->ProFile){
/*    2  PB1=BSY                */  retval |= (V->ProFile->BSYLine     ? 0 : BSYLine_BIT);  // busy line? (inverted)
/*    4  PB2=DEN                */  retval |= (V->ProFile->DENLine     ? 0 : DENLine_BIT);  // disk enable line?
/*    8  PB3=RRW                */  retval |= (V->ProFile->RRWLine     ? 0 : RRWLine_BIT);  // read or write
/*   16  PB4=CMD                */  retval |= (V->ProFile->CMDLine     ? 0 : CMDLine_BIT);  // command
/*   32  PB5=Parity (always=0)  */      // do nothing, this should always return 0 for no parity errors
		V->ca1=V->ProFile->BSYLine;

        if (pc24<0x00fe0000) print_via_profile_state("via_irb ", retval,V);

        return retval;
	}
    else if (V->ADMP)
           {
             retval =  0; //BSYLine_BIT (0=ACK), OCD (1=Paper Out, 0=ok)
             DEBUG_LOG(0,"Read from ADMP IRB - returning BSYLine");
             return retval; // ADMP doesn't return anything far as I know
           }
    else if (V->irb!=NULL)  return V->irb(V->vianum,regnum);

	return 0; // nothing attached, ignore.
}


uint8 via2_ira(uint8 regnum)
{
    VIA_CLEAR_IRQ_PORT_A(2); // clear CA1/CA2 on ORA/IRA access
    //if (debug_log_enabled) fdumpvia2(buglog);
    // driver enable is off, don't process ADMP/Profile data output - not sure if this is correct.

    if (via[2].via[ORBB] & via[2].via[DDRB] & 4) {DEBUG_LOG(0,"Returning Contrast"); return contrast;}

    if (via[2].ProFile) // Is this a profile?
	{
        VIAProfileLoop(2,via[2].ProFile,PROLOOP_EV_IRA);
        via[2].via[IRA]=via[2].ProFile->VIA_PA;
        DEBUG_LOG(0,"profile.c:READ %02x from ProFile, pc24:%08x  tag:profile state:%d",via[2].via[IRA],pc24,via[2].ProFile->StateMachineStep);
        return via[2].via[IRA];
	}
	else if (via[2].ADMP) return 0; // ADMP doesn't return anything far as I know
    //else if (via[2].ira!=NULL) return via[2].ira(2,regnum); // Some other thing attached.

	return 0; // nothing attached, ignore.
}


//lisa_rb_Oxd800_par_via2(uint32 addr)
void  via2_ora(uint8 data, uint8 regnum)
{
    VIA_CLEAR_IRQ_PORT_A(2); // clear CA1/CA2 on ORA/IRA access


    DEBUG_LOG(0,"ORA:%02x DDRA:%02x   ORB:%02x DDRB:%0x",via[2].via[ORA],via[2].via[DDRA],via[2].via[ORB],via[2].via[DDRB]);
    if (via[2].via[DDRA]==0) return;    // can't write just yet, ignore.
    if ( check_contrast_set()) return;


    if (via[2].via[ORBB] & via[2].via[DDRB] & 4) return;    // driver enable is off, don't process ADMP/Profile data output.
    via[2].orapending=0;

    //if (debug_log_enabled) fdumpvia2(buglog);
    if (via[2].ProFile) // Is this a profile?
	{
        DEBUG_LOG(0,"profile.c:Sending byte %02x from via2_ora to ProFile code pc24:%08x tag:profile step:%d @%d",
                data,
                pc24,
                via[2].ProFile->StateMachineStep,via[2].ProFile->indexwrite);
        via[2].ProFile->VIA_PA=data;  via[2].via[ORA]=data; via[2].ProFile->last_a_accs=1; //20060323//
        VIAProfileLoop(2,via[2].ProFile,PROLOOP_EV_ORA);

        return;
	}

    if (via[2].ADMP) {via[2].via[ORA]=data; ImageWriterLoop(via[2].ADMP,data); return;}
}



void via2_orb(uint8 data)
{
    #ifdef DEBUG
     uint8 flipped=((data^via[2].via[ORBB]) & (via[2].via[DDRB]) );
    #endif

    VIA_CLEAR_IRQ_PORT_B(2); // clear Cb1/Cb2 on ORb/IRb access

    // Setting Contrast - DEN is off, PB7 is used as Strobe.
    if ( check_contrast_set()) return;


    // Is there an attached ProFile device on this parallel port?
	if (via[2].ProFile){

    // Push the ORB bits to the ProFile flags. (OCD/BSY/DSKDiag/PARITY_BIT are inputs, so we don't do them, hence they're
    // commented out, but left in for the sake of completeness / being pendantic, fasict, totalitarian, etc.
    //------------------------------------------------------------------------------------------------------------------------------------
    //  if ( OCDLine_BIT & via[2].via[DDRB]) {via[2].ProFile->DENLine=(data & OCDLine_BIT) ? 0:1;}   //0 Ignored - hardwired input only line
    //  if ( BSYLine_BIT & via[2].via[DDRB]) {via[2].ProFile->BSYLine=(data & BSYLine_BIT) ? 0:1;}   //1 Ignored - hardwired input only line
        if ( DENLine_BIT & via[2].via[DDRB]) {via[2].ProFile->DENLine=(data & DENLine_BIT) ? 0:1;}   //2 DEN - drive enable....
        if ( RRWLine_BIT & via[2].via[DDRB]) {via[2].ProFile->RRWLine=(data & RRWLine_BIT) ? 0:1;}   //3 RRW is 1=write, 0=read from port
        if ( CMDLine_BIT & via[2].via[DDRB]) {via[2].ProFile->CMDLine=(data & CMDLine_BIT) ? 0:1;}   //4 CMD line
    //  if ( PARITY_BIT   & via[2].via[DDRB]) {via[2].ProFile->Parity=(data &  PARITY_BIT) ? 0:1;}   //5 Parity error bit is input
        if ( DSK_DIAG_BIT & via[2].via[DDRB]) {DEBUG_LOG(0,"Write to DSK_DIAG on via2_orb!:%02x",data & DSK_DIAG_BIT);} // 6 Floppy Disk Diag is input

        // this is wrong, reet is on VIa1!
       // if ( CTRL_RES_BIT & via[2].via[DDRB]) {if ((data & CTRL_RES_BIT)==0)                         //7 Controller reset
       //                                           { DEBUG_LOG(0,"Sent Controller Reset to ProFile:%02x",data & CTRL_RES_BIT);
       //                                             ProfileReset(via[2].ProFile);
       //                                           }
       //                                       }

        DEBUG_LOG(0,"profile.c:ORA:%02x DDRA:%02x   ORB:%02x DDRB:%0x",via[2].via[ORA],via[2].via[DDRA],via[2].via[ORB],via[2].via[DDRB]);
        DEBUG_LOG(0,"profile.c:pb0:!OCD:%d pb1:!BSY:%d pb2:!DEN:%d pb3:!DR/W/:%d pb4:!CMD/:%d pb5:PRES:%d pb6:DIAGWait:%d pb7:CTRL_RES:%d = Data=%02x",
                    (data&1),(data&2),(data&4),(data&8),(data&16),(data&32),(data&64),(data&128),data);

        DEBUG_LOG(0,"Flipped bits: %s%s%s%s%s%s%s%s",((flipped &    1) ? "OCD:pb0 ":"    ")
                                                   , ((flipped &    2) ? "BSY:pb1 ":"    ")
                                                   , ((flipped &    4) ? "DEN:pb2 ":"    ")
                                                   , ((flipped &    8) ? "RRW:pb3 ":"    ")
                                                   , ((flipped &   16) ? "CMD:pb4 ":"    ")
                                                   , ((flipped &   32) ? "PAR:pb5 ":"    ")
                                                   , ((flipped &   64) ? "DSK:pb6 ":"    ")
                                                   , ((flipped &  128) ? "CRS:pb7 ":"    ") );

		via[2].ca1=via[2].ProFile->BSYLine;	// refresh


        DEBUG_LOG(0,"before Lines DEN:%d RRW:%d CMD:%d",
                via[2].ProFile->DENLine,via[2].ProFile->RRWLine,via[2].ProFile->CMDLine);


 //       if (pc24<0x00fe0000) print_via_profile_state("\nvia2_orb pre-loop ", data,&via[2]);
 //       if (debug_log_enabled) fdumpvia2(buglog);
        VIAProfileLoop(2,via[2].ProFile,PROLOOP_EV_ORB);



        if (pc24<0x00fe0000) print_via_profile_state("\nvia2_orb post-loop ", data,&via[2]);
	}

    // Is there an attached dot matrix printer?
    if (via[2].ADMP) return;       // Output to Apple Dot Matrix Printer -- not yet implemented

	return; // nothing attached, ignore.
}




uint8 via2_irb(void) //this is good
{
    // remove these two.
    //static uint32 lastpc;
    //static uint32 lastpccount;

    uint8 retval=0;

     //floppy_6504_wait=!floppy_6504_wait;

     VIA_CLEAR_IRQ_PORT_B(2); // clear Cb1/Cb2 on ORb/IRb access

     // return the values of the previous output bits
     ///retval = via[2].via[IRB] & via[2].via[DDRB];  //20060110 - no longer needed

     if (floppy_ram[0]) {floppy_go6504();}  // if this is being read, it's likely Lisa is waiting on floppy, so speed it up

     // set up the return of the common bits before we deal with attached devices
     retval |= (floppy_6504_wait  ? 0:DSK_DIAG_BIT);  // return floppy diag bit
     retval |= (  ((via[2].ProFile || via[2].ADMP) && floppy_picked && powerfile_power) ? 0 : OCDLine_BIT);  // ADMP/Profile attached?

     if (via[2].ProFile){

        if (pc24<0x00fe0000) print_via_profile_state("\nvia2_irb pre-loop ", via[2].via[IRB],&via[2]);

        // BSY is controlled by the profile, while DEN, RRW, and CMD are controlled by Lisa.  Lisa bits must be set before
        // entering the ProFile loop - and they are from via2_orb, while BSY must be set after the call to ProFile loop,
        // however, we set the rest of the bits in retval to return them to the Lisa as expected and to verify correctness.

        VIAProfileLoop(2,via[2].ProFile,PROLOOP_EV_IRB);

        // update return values from ProFile handshake/comm bits
        via[2].ca1=via[2].ProFile->BSYLine;

        // Next four lines do the same thing as their uncommented versions below.  Leaving commented version in for clarity.
        //if (!(via[2].via[DDRB] & BSYLine_BIT)) retval |= (via[2].ProFile->BSYLine ? 0 : BSYLine_BIT); else retval |=(via[2].via[IRB] & BSYLine_BIT);
        //if (!(via[2].via[DDRB] & DENLine_BIT)) retval |= (via[2].ProFile->DENLine ? 0 : DENLine_BIT); else retval |=(via[2].via[IRB] & DENLine_BIT);
        //if (!(via[2].via[DDRB] & RRWLine_BIT)) retval |= (via[2].ProFile->RRWLine ? 0 : RRWLine_BIT); else retval |=(via[2].via[IRB] & RRWLine_BIT);
        //if (!(via[2].via[DDRB] & CMDLine_BIT)) retval |= (via[2].ProFile->CMDLine ? 0 : CMDLine_BIT); else retval |=(via[2].via[IRB] & CMDLine_BIT);

        // If the DDRB bit is an input return the value sent by the profile, otherwise return the previous value of that bit from the old IRB
        retval |= (!(via[2].via[DDRB] & BSYLine_BIT)) ? (via[2].ProFile->BSYLine ? 0 : BSYLine_BIT) : (via[2].via[IRB] & BSYLine_BIT);
        retval |= (!(via[2].via[DDRB] & DENLine_BIT)) ? (via[2].ProFile->DENLine ? 0 : DENLine_BIT) : (via[2].via[IRB] & DENLine_BIT);
        retval |= (!(via[2].via[DDRB] & RRWLine_BIT)) ? (via[2].ProFile->RRWLine ? 0 : RRWLine_BIT) : (via[2].via[IRB] & RRWLine_BIT);
        retval |= (!(via[2].via[DDRB] & CMDLine_BIT)) ? (via[2].ProFile->CMDLine ? 0 : CMDLine_BIT) : (via[2].via[IRB] & CMDLine_BIT);


        if ((via[2].via[DDRB] & PARITY_BIT)==0) retval|=(eparity[via[2].via[ORA]] ? PARITY_BIT:0);  // re-enabled 2006.05.24
      //  if ((via[2].via[DDRB] & PARITY_BIT)==0) retval|=(eparity[via[2].via[ORA]] ? 0:PARITY_BIT);  // re-enabled 2006.05.25


        if (pc24<0x00fe0000) print_via_profile_state("\nvia2_irb post-loop ", retval,&via[2]);

        ///////////////////////////////////////////////////////////
        DEBUG_LOG(0,"Returning: %02x from via2_irb ProFile code",retval);
        DEBUG_LOG(0,"profile.c:ORA:%02x DDRA:%02x   ORB:%02x DDRB:%0x",via[2].via[ORA],via[2].via[DDRA],via[2].via[ORB],via[2].via[DDRB]);
        via[2].via[IRB]=retval;    return retval;
     }
     else if (via[2].ADMP!=0)
           {
             retval =  BSYLine_BIT;
             DEBUG_LOG(0,"Returning BSYLine");
             return retval; // ADMP doesn't return anything far as I know
           }

     else if (via[2].irb) return via[2].irb(2,IRB);

    //retval |=0x02;   // Set ProFile busy line, since there isn't once attached.
    //retval |=4;      // Set Disk Enable Line to no drive there.

     DEBUG_LOG(0,"profile.c:pb0:!OCD:%d pb1:!BSY:%d pb2:!DEN:%d pb3:DR/W/:%d pb4:!CMD/:%d pb5:!PRES:%d pb6:DIAGWait:%d pb7:CTRL_RES:%d = Data=%02x",
                    (retval&1),(retval&2),(retval&4),(retval&8),(retval&16),(retval&32),(retval&64),(retval&128),retval);


     //if (debug_log_enabled) fdumpvia2(buglog);
     via[2].via[IRB]=retval;    return retval;
}




uint8 via1_irb(uint8 reg)
{
    uint8 data=0;


    data=via[1].via[ORB] & via[1].via[DDRB];  // allow Lisa to read back the outputs?

    DEBUG_LOG(0,"SRC: VIA1/COPS: reading reg %d port B",reg);

    VIA_CLEAR_IRQ_PORT_B(1); // clear Cb1/Cb2 on ORb/IRb access

    data |=((volume & 0x07)<<1);            // PB1-3 is volume
    //data=via[1].via[IRB] & (255-16-64); // get whatever's in the register, except for stuff we set:FDIR,CRDY

    // If lisa is reading this, it might be waiting on FDIR - so speed it up
    if (floppy_ram[0])   {floppy_go6504();}

    //data |=(floppy_FDIR ? 16: 0);

    if ( floppy_FDIR) {data |=16;  DEBUG_LOG(0,"FDIR=1 returned via1_irb\n");/*floppy_FDIR=0;*/}      // was just 4, 16 didn't work, now I'm trying 16|4
    else DEBUG_LOG(0,"FDIR=0 returned via1_irb\n");


   // Is there a ProFile on VIA2? - yes, some lines are crossed between VIA1 and VIA2 - likely a legacy design bug before ProFiles
   if (via[2].ProFile)
   {

      data &=~32;
      data |=(eparity[via[2].ProFile->VIA_PA] ? 32:0);  // was via[2].via[ORA]

      if (data & 128) data |=32;                        // when PB7=1 means ProFile is being reset, LisaTest expects PB5=1 too

      DEBUG_LOG(0,"Last ORA:%02x - Parity:%02x, DDRB:%d returning:%d",
                   via[2].via[ORA],
                   !eparity[via[2].via[ORA]],
                   (via[1].via[DDRB] & 32),
                   data & 32);

      //if ((via[2].via[DDRB] & PARITY_BIT)==0) data|=(eparity[via[2].via[ORA]] ? PARITY_BIT:0);
   }
   else DEBUG_LOG(0,"No Profile attached to Parallel Port!");

   // if ((via[2].via[DDRB] & PARITY_BIT)==0) data|=(eparity[via[2].via[ORA]] ? PARITY_BIT:0);



    // toggle ready on and off all the time to stimulate handshaking process - when data is ready on the COPS?

   crdy_toggle=(crdy_toggle+1) & 3;
   // crdy_toggle = !crdy_toggle; //pb6 goes to D3 on COPS CA1,CA2 goes to S0,S1 on COPS. L0-L7=PA0-PA7.
    if (  crdy_toggle )  {data= data | 0x40;  DEBUG_LOG(0,"via1_irb: COPS: CRDY is on");}  // PB6 //
    else                 {data= data & (0xff - 0x40); DEBUG_LOG(0,"via1_irb: COPS: CRDY is off");}

    //20060609-1750//if (copsqueuelen>0 || mousequeuelen>0)   data |= 0x40;
    //20060609-1750//else                                     data &=~0x40;



    DEBUG_LOG(0,"SRC: COPS: copsqueuelen=%d",copsqueuelen);
    DEBUG_LOG(0,"SRC: COPS: returning data: %02x & %02x = %02x",data,via[1].via[DDRB]^0xff,   data & (~via[1].via[DDRB]) );


    DEBUG_LOG(0,"via1_irb: pb1-3volume:%d  pb4:%s pb6:%s pb0:%s pb5:%s pb7:%s\n",
            ((data>>1) & 7),
            ((data & 16)  ? "FDIR=1":"FDIR=0"),
            ((data & 64)  ? "COPS_CRDY=1":"COPS_CRDY=0"),
            ((data & 1)   ? "COPS_KB_RESET=1":"COPS_KB_reset=off"),
            ((data & 32)  ? "Parity=On":"Parity=Off"),
            ((data & 128) ? "Parallel_Controller_Reset=On":"Parallel_Controller_Reset=Off")
            );


    return data & (~via[1].via[DDRB]);
}


void via1_orb(uint8 data)
{
    //unused???//uint8 xdata=data & via[1].via[DDRB];
            #ifdef DEBUG
             uint8 flipped=(  (via[1].via[ORB] ^ data) & via[1].via[DDRB] );


             DEBUG_LOG(0,"Writing VIA1 ORB. DDRB mask=%02x:(%s%s%s%s%s%s%s%s)",via[1].via[DDRB],
                                ( (via[1].via[DDRB] &    1) ?"PB0:out ":"pb0:in  "),
                                ( (via[1].via[DDRB] &    2) ?"PB1:out ":"pb1:in  "),
                                ( (via[1].via[DDRB] &    4) ?"PB2:out ":"pb2:in  "),
                                ( (via[1].via[DDRB] &    8) ?"PB3:out ":"pb3:in  "),
                                ( (via[1].via[DDRB] &   16) ?"PB4:out ":"pb4:in  "),
                                ( (via[1].via[DDRB] &   32) ?"PB5:out ":"pb5:in  "),
                                ( (via[1].via[DDRB] &   64) ?"PB6:out ":"pb6:in  "),
                                ( (via[1].via[DDRB] &  128) ?"PB7:out ":"pb7:in  "));

             DEBUG_LOG(0,"VIA1 ORB bits Flipped  :(%s%s%s%s%s%s%s%s)",
                                (( flipped &    1) ?"PB0_kb reset.":" "),
                                (( flipped &    2) ?"PB1 vol.":" "),
                                (( flipped &    4) ?"PB2 vol.":" "),
                                (( flipped &    8) ?"PB3 vol.":" "),
                                (( flipped &   16) ?"PB4 FDIR.":" "),
                                (( flipped &   32) ?"PB5 !PRES.":" "),
                                (( flipped &   64) ?"PB6 cops_handshake.":" "),
                                (( flipped &  128) ?"PB7 profile_reset.":" "));

             DEBUG_LOG(0,"VIA1 ORB write=%02x:(COPSRESET:%s Volume:%d FDIR:%s PRES:%s COPSHANDSHAKE:%s ProRESET:%s)",data,
                                (( data &    1) ?"PB0:1no_reset ":"PB0:0-RESET "),
                                (( data>>1)& 7),
                                (( data &   16) ?"PB4:1 ":"PB4:0 "),
                                (( data &   32) ?"PB5:1 ":"PB5:0 "),
                                (( data &   64) ?"PB6:1 ":"PB6:0 "),
                                (( data &  128) ?"PB7:1 ":"PB7:0 "));

            #endif


    VIA_CLEAR_IRQ_PORT_B(1); // clear Cb1/Cb2 on ORb/IRb access


    DEBUG_LOG(0,"SRC: COPS:handshake VOLUME: FDIR: Profile:reset outputting %02x to VIA1 ORB",data);

    via[1].via[ORB]=data;

    if (0x01 & via[1].via[DDRB]) {if (!(data & 1)) cops_reset();}  // Reset Cops when PB0=0

	// Set sound volume PB1-3
    if (  (via[1].via[DDRB] & 0x0e)) {volume=((volume<<1)&(0x0e^(via[1].via[DDRB] & 0x0e)))|(data & via[1].via[DDRB] & 0x0e)>>1; return ;}

	// Do I need this here???
    //if (via[1].via[DDRB]) floppy_FDIR=(data & 0x10 ? 1:0); // Is Lisa trying to clear or set FDIR?
    if (via[1].via[DDRB] & 16) {DEBUG_LOG(0,"Lisa attempting to clear/set FDIR  %02x -> %02x\n",data, data & 16); }
//                              floppy_FDIR=(data&16 ? floppy_FDIR:0); }      // Is Lisa trying to clear FDIR?

    if (data & 32 & via[1].via[DDRB]) {DEBUG_LOG(0,"lisa writing to Parity RESET: %02x ->%02x\n",data, data & 0x40);} // PRES/ Parity Reset

    if (data & 64 & via[1].via[DDRB]) {DEBUG_LOG(0,"lisa writing to cops handshake: %02x ->%02x\n",data, data & 0x40);} // cops handshake
	// PB7=CRES/

    if (0x80 & via[1].via[DDRB])
        {
            DEBUG_LOG(0,"via1_orb ProFile !RESET :%02x %02x (0 means no reset, 80 means reset)\n",data,data & 0x80); //20051214 flipped
            if (  ( (data & 0x80)) && via[2].ProFile) ProfileReset(via[2].ProFile);
        }  // PB7 = reset Profile

    return;



}




/***********************************************************************************\
*  Functions to handle VIA I/O for VIA1 (COPS microcontroller interface.) and the   *
*  Playing of sounds, volume.                                                       *
*                                                                                   *
*  Note CA1 is always input here.  CA2 handshakes with COPS PA talks to COPS.       *
*                                                                                   *
*  PortB:                                                                           *
*    PB7  - CR/  - reset hard drive controller when low                             *
*    PB6  - CRDY - COPS ready line - high to low when ready                         *
*    PB5  - PR/  - Parity reset - low true                                          *
*    PB4  - FDIR - Floppy IRQ FDIR=1 floppy op=safe for 68k to read result          *
*    PB3  - PR/ (Parity Reset - low true)                                           *
*    PB2  ---- find out what these do these days ----                               *
*    PB1                                                                            *
*    PB0                                                                            *
*                                                                                   *
*    CB1  -- was used to clock CVSD circuit                                         *
*    CB2  -- ditto what's their purpose now a days????                              *
\***********************************************************************************/


/*

* Contrast Control On PARALLEL PORT VIA!                                               *
*                                                                                      *
* Contrast Control Circuitry is located on the I/O board.  A d/a converter controls the*
* CRT display contrast, this is controlled by a latch connected to the Slow Data bus   *
* (hard disk interface 6522 peripheral port A.) To write a value to the contrast       *
* latch:  1. Set the DEN bit (PB2) to 1.  2. Put contrast $00-$FF in port A on the     *
* hard disk 6522.  3. Execute MOVE.L D0,$00D01C this causes a pulse on the contrast    *
* latch clock input.   <- not true in ROM                                              *
*                                                                                      *
* The address $00D01C in the I/O address space clears the clock input to the contrast  *
* latch.  The $00D01E sets the clock input so the MOVE instruction given above insures *
* that there is a positive edge on the clock input.                                    *
*                                                                                      *
* When the system is reset either by the RESET instruction, or by a power-on, the      *
* contrast latch is reset and the screen is cleared.  The higher the number stored in  *
* the constrast latch, the higher the display contrast.                                *
*                                                                                      *
*
* should be 0xFCD01C for Contrast Latch...
*
*/

void chk_sound_play(void)
{
            if  (  via[1].via[SHIFTREG]!=0 && via[1].via[T2LL]!=0  && ((via[1].via[ACR] & 0x10)==0x10) )
			{
                sound_play( via[1].via[T2LH]<<8 | (via[1].via[T2LL] ) ); // enable sound, smaller the higher the pitch.
                return;
			}

            if ((via[1].via[ACR] & 0x10)==0) sound_off();               // otherwise, STFU
}


void lisa_wb_Oxdc00_cops_via1(uint32 addr, uint8 xvalue)
{

    via[1].active=1;                        // these are always active as they're on the
    via[2].active=1;                        // motherboard of the machine...


    #ifdef DEBUG
    if (!(addr & 1)) { DEBUG_LOG(0,"will ignore illegal address access to %08x write value=%02x",addr,xvalue); }
    else             { DEBUG_LOG(0,"writing %02x to register %d (%s)", xvalue, (addr -VIA1BASE)/2 ,via_regname((addr -VIA1BASE)/2) ); }
    #endif


    switch (addr & 0x1f)
	{
        case ORB1  :
                   /* It is possible to write multiple bytes by writing different
                    * sized values out the VIA - this is used by the parallel via
                    * for "speed", so we need to check the sizes.  Now since you
                    * can't write to the port unless the Data Direction Reg bits
                    * are on, we do an AND with them before writing out.         This is handled by the MMU! */

            VIA_CLEAR_IRQ_PORT_B(1); // clear Cb1/Cb2 on ORb/IRb access

            DEBUG_LOG(0,"ORB1");
            via[1].via[ORB]=xvalue; DEBUG_LOG(0,"VIA1 ORB(NH)=%02x",via[1].via[ORB]);// set the register to the unmasked data for later use.
            if ( !via[1].via[DDRB]) return;  // don't write anything if the DDRA is all inputs
            via1_orb(via[1].via[ORB] & via[1].via[DDRB]); // output the masked data.
            return;

		case ORANH1 : //IRA/ORA
            via[1].last_a_accs=1;
            DEBUG_LOG(0,"ORANH1");
            via[1].via[ORAA]= xvalue;
            via[1].via[ORA]= xvalue;
            DEBUG_LOG(0,"VIA1 ORA(NH)=%02x DDRA=%02x",via[1].via[ORA],via[1].via[DDRA]);
            if ( !via[1].via[DDRA]) return;  // don't write anything if the DDRA is all inputs
            via1_ora((via[1].via[ORA] & via[1].via[DDRA]),15);
			return;

		case ORA1   :
            via[1].last_a_accs=1;
            VIA_CLEAR_IRQ_PORT_A(1); // clear CA1/CA2 on ORA/IRA access

            DEBUG_LOG(0,"ORA1");
            via[1].via[ORAA]= xvalue;   DEBUG_LOG(0,"VIA1 ORA=%02x DDRA=%02x",via[1].via[ORA],via[1].via[DDRA]);
            via[1].via[ORA]= xvalue;
            if ( !via[1].via[DDRA]) return;  // don't write anything if the DDRA is all inputs
            via1_ora(via[1].via[ORAA] & via[1].via[DDRA],ORA); //output the masked data
			return;

		case DDRB1  :         // DDRB 2
            DEBUG_LOG(0,"DDRB1");


            if ( xvalue && xvalue!=via[1].via[DDRB] )                  // only try the write if the mask has changed
                {   via[1].via[DDRB]=xvalue;                           // do not optimize this out!
                    via1_orb(via[1].via[ORBB] & via[1].via[DDRB]);     // output the data that was masked off
                    return;
                }
            else  via[1].via[DDRB]=xvalue;


            return;

		case DDRA1  :         // and DDRA 3 registers
            DEBUG_LOG(0,"DDRA1");

            if ( xvalue && xvalue!=via[1].via[DDRA] )                  // only try the write if the mask has changed
                {   via[1].via[DDRA]=xvalue;                           // do not optimize this out!
                    via1_ora(via[1].via[ORAA] & via[1].via[DDRA],ORA); // output the data that was masked off
                    return;
                }
            else  via[1].via[DDRB]=xvalue;

            via[1].via[DDRA]=xvalue;

            //if ( via[1].last_a_accs && xvalue!=0) // only try to write if this mask changed and last access to A was a write
            //    via1_ora(via[1].via[ORA] & via[1].via[DDRA],ORA);                   //output the masked data
            return;

/*

read from register
4 T1LC read - T1 IRQ flag cleared (bit 6 in IRQ flag register)
5 T1CH read - no comment on reset of T1 IRQ flag
6 T1LL read - does not reset T1 IRQ flag!
7 T1HL read - no comment on reset of T1 IRQ flag ?

write to register
4 T1LC actually writes to T1LL only
5 T1HC actually writes to T1HL + copies T1LL->T1CL, T1LH->T1CH
6 T1LL same as write to reg4
7 T1HL value copied into T1HL, no transfer to T1CH
*/

        case T1LL1  :                                                              // Timer 1 Low Order Latch
            DEBUG_LOG(0,"T1LL1");                                                  // 6 T1LL same as write to reg4
            via[1].via[T1CL]=xvalue;                                               // 4 T1LC actually writes to T1LL only
            via[1].via[T1LL]=xvalue;
            via[1].t1_e=get_via_te_from_timer((via[1].via[T1LH]<<8)|via[1].via[T1LL]);

            FIX_CLKSTOP_VIA_T1(1);      // update cpu68k_clocks_stop if needed

            //#ifdef DEBUG
            via[1].t1_set_cpuclk=cpu68k_clocks;
            //#endif
            via_running=1;
            DEBUG_LOG(0,"ll-t1clk:%d T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((via[1].via[T1LH]<<8)|via[1].via[T1LL]) , via[1].t1_e, via[1].t1_e-cpu68k_clocks,cpu68k_clocks);

            return;

		case T1LH1  :
            DEBUG_LOG(0,"T1LH1");                                                  // 7 T1HL value copied into T1HL, no transfer to T1CH
            via[1].via[T1LH]=(xvalue);                                             // Set timer1 latch and counter
            via_running=1;
            //2005.05.31 - this next line was disabled - should it have been?
            //via[1].t1_e=get_via_te_from_timer((via[1].via[T1LH]<<8)|via[1].via[T1LL]);
            // VIA_CLEAR_IRQ_T1(1);     // clear T1 irq on T1 read low or write high - does this clear the timer?

            DEBUG_LOG(0,"lh-t1clk:%d (%04x) t1lh1=%02x T1 will now expire at:%ld - %llx cycles from now - clock now:%llx",
                    ((via[1].via[T1LH]<<8)|via[1].via[T1LL]) ,
                    ((via[1].via[T1LH]<<8)|via[1].via[T1LL]) , xvalue,
                    via[1].t1_e,
                    via[1].t1_e-cpu68k_clocks,cpu68k_clocks);

            return;

        case T1CL1  :                                                              // 4 T1LC actually writes to T1LL only
            DEBUG_LOG(0,"T1CL1");
            via[1].via[T1LL]=xvalue;

            //via[1].t1_e=get_via_te_from_timer((via[1].via[T1LH]<<8)|via[1].via[T1LL]);   // so, does this still count down? likely not!
            //FIX_CLKSTOP_VIA_T1(1);      // update cpu68k_clocks_stop if needed           // disable this code here.
            // via[1].t1_set_cpuclk=cpu68k_clocks;

            via_running=1;

            DEBUG_LOG(0,"cl-t1clk:%d (%04x) CL1=%02x T1 will now expire at:%llx - %lld cycles from now - clock now:%llx",
                    ((via[1].via[T1LH]<<8)|via[1].via[T1LL]) ,
                    ((via[1].via[T1LH]<<8)|via[1].via[T1LL]) , xvalue,
                    via[1].t1_e, via[1].t1_e-cpu68k_clocks,cpu68k_clocks);

            return;



		case T1CH1  :
            DEBUG_LOG(0,"T1CH1");
            if ( via[1].via[ACR]&128) via[1].via[IRB] &= 0x7f;                             // with ACR7=1, a write to T1C brings PB7 low
            via[1].via[T1LH]=xvalue;                                                       // load into register
            via[1].via[T1CH]=via[1].via[T1LH]; via[1].via[T1CL]=via[1].via[T1LL];          // 5 T1HC actually writes to T1HL + copies T1LL->T1CL, T1LH->T1CH

            via[1].t1_e=get_via_te_from_timer((via[1].via[T1CH]<<8)|via[1].via[T1LL]);     // this one does tell the counter to count down!
            FIX_CLKSTOP_VIA_T1(1);                                                         // update cpu68k_clocks_stop if needed
            via[1].t1_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)

            VIA_CLEAR_IRQ_T1(1);     // clear T1 irq on T1 read low or write high

            DEBUG_LOG(0,"ch-t1clk:%d (%04x) CH1=%02x T1 will now expire at:%ld - %llx cycles from now - clock now:%llx",
                    ((via[1].via[T1LH]<<8)|via[1].via[T1LL]),
                    ((via[1].via[T1LH]<<8)|via[1].via[T1LL]), xvalue,
                    via[1].t1_e, via[1].t1_e-cpu68k_clocks,cpu68k_clocks);

            via_running=1;

			return;


		case T2CL1  :  // Set Timer 2 Low Latch
            DEBUG_LOG(0,"T2CL1");
            via[1].via[T2LL]=xvalue;                                                       // Set t2 latch low
            //via[1].via[T2CL]=xvalue;                                                       // NOT SURE ABout this one!  2004.12.02
            // no change to the counter! only the latch! //2005.06.05
            // via[1].t2_e=get_via_te_from_timer((via[1].via[T2LH]<<8)|via[1].via[T2CL]);     // set timer expiration
            //FIX_CLKSTOP_VIA_T2(1);                                                         // update cpu68k_clocks_stop if needed
            //via[1].t2_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)


            //#ifdef DEBUG
            via[1].t2_set_cpuclk=cpu68k_clocks;
            DEBUG_LOG(0,"t2clk:%d (write takes effect on write to T2H) T2 set to expire at CPU clock:%llx time now is %llx which is %llx cycles from now",
                    ((via[1].via[T2LH]<<8)|via[1].via[T2CL]),via[1].t2_e,cpu68k_clocks,via[1].t2_e-cpu68k_clocks);
            //#endif
            via_running=1;
            chk_sound_play();
            return;



		case T2CH1  : // timer2 high byte
              // a write to T2H will load and the counter as well.
            DEBUG_LOG(0,"T2CH1");

            via[1].via[T2LH]=xvalue;                                                       // Set t2 latch high
            via[1].via[T2CH]=xvalue; via[1].via[T2CL]=via[1].via[T2LL];                    // load the counter with latches

            VIA_CLEAR_IRQ_T2(1);     // clear T2 irq on T1 read low or write high
            via[1].t2_e=get_via_te_from_timer((via[1].via[T2LH]<<8)|via[1].via[T2CL]);     // set timer expiration
            FIX_CLKSTOP_VIA_T2(1);                                                         // update cpu68k_clocks_stop if needed
            via[1].t2_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)

            DEBUG_LOG(0,"t2clk:%d T2 set to expire at CPU clock:%llx time now is %llx which is %llx cycles from now",
                    ((via[1].via[T2LH]<<8)|via[1].via[T2CL]),via[1].t2_e,cpu68k_clocks,via[1].t2_e-cpu68k_clocks);

            via_running=1;
            chk_sound_play();
			return;


		case SR1 :  /*
                * If the VIA1 SR has been written to by any value other than zero,
                * the Lisa is trying to beep.  T2Low is the Frequency.
                * The lisa will continue to play tones until SR=0 or ACR1
                * disables free run on T2.
                */
            DEBUG_LOG(0,"SR1");
            via[1].via[SHIFTREG]=xvalue;                     // write shift register
            via_running=1;
            via[1].srcount=0;
            VIA_CLEAR_IRQ_SR(1);     // clear SR irq on SR access

                    // now if this has really be done, then we need to know if actual
                    // data is in here or zero's or ones.

                    // make sure we're not writing all 1's or all 0's, AND the timer is set, AND set to free run.
            chk_sound_play();
            return;

        case ACR1 :

                    DEBUG_LOG(0,"ACR1 Port A Latching:%s  Port B Latching:%s",( (xvalue & BIT0) ? "Enabled":"Disabled"), ((xvalue & BIT1) ? "Enabled":"Disabled") );
                    #ifdef DEBUG

                    switch(xvalue & (BIT4|BIT3|BIT2)>>2)  {
                      case 0: DEBUG_LOG(0,"ACR1 SHIFT REG DISABLED");                    break;
                      case 1: DEBUG_LOG(0,"ACR1 SR SHIFT IN UNDER COMTROL OF T2");       break;
                      case 2: DEBUG_LOG(0,"ACR1 SR SHIFT IN UNDER CONTROL OF 02");       break;
                      case 3: DEBUG_LOG(0,"ACR1 SR SHIFT IN UNDER CONTROL OF EXT.CLK");  break;
                      case 4: DEBUG_LOG(0,"ACR1 SR SHIFT OUT FREE-RUNNING AT T2 RATE");  break;
                      case 5: DEBUG_LOG(0,"ACR1 SR SHIFT OUT UNDER CONTROL OF T2");      break;
                      case 6: DEBUG_LOG(0,"ACR1 SR SHIFT OUT UNDER CONTROL OF 02");      break;
                      case 7: DEBUG_LOG(0,"ACR1 SR SHIFT OUT UNDER CONTROL OF EXT.CLK"); break;
                    }

                    DEBUG_LOG(0,"ACR1 Timer2 Control: %s", ((xvalue & BIT6) ? "Countdown with PB6 Pulses":"Timed IRQ"));

                    switch(xvalue & (BIT7|BIT6)>>6)  {
                      case 0: DEBUG_LOG(0,"ACR1 Timer1 Control: TIMED IRQ Each Time T1 Loaded, PB7 Output Disabled"); break;
                      case 1: DEBUG_LOG(0,"ACR1 Timer1 Control: CONTINUOUS IRQ's, PB7 Output Disabled"); break;
                      case 2: DEBUG_LOG(0,"ACR1 Timer1 Control: TIMED IRQ Each Time T1 is loaded, PB7 - One Shot Output"); break;
                      case 3: DEBUG_LOG(0,"ACR1 Timer1 Control: Continous IRQ's, PB7: SQUARE WAVE OUTPUT"); break;
                    }
                    #endif
                    via[1].via[ACR]=xvalue;
                    chk_sound_play();
                    return;

        case PCR1 : DEBUG_LOG(0,"PCR1: ca1 irq ctl:%s active edge",((xvalue & BIT0) ? "1:positive":"0:negative") );
                    #ifdef DEBUG
                    switch((xvalue & 15)>>1) {
                      case 0 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE"); break;
                      case 1 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT Input NEG. Active Edge"); break;
                      case 2 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE"); break;
                      case 3 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT INPUT POSITIVE Active Edge"); break;
                      case 4 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: HANDSHAKE OUTPUT"); break;
                      case 5 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: PULSE OUTPUT"); break;
                      case 6 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: LOW OUTPUT"); break;
                      case 7 : DEBUG_LOG(0,"PCR1: CA2 INTERRUPT CONTROL: HIGH OUTPUT"); break;
                    }
                    DEBUG_LOG(0,"PCR1: cb1 irq ctl:%s active edge",((xvalue & BIT4) ? "1:positive":"0:negative") );
                    switch((xvalue & (BIT7|BIT6|BIT5))>>5) {
                      case 0 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE"); break;
                      case 1 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT Input NEG. Active Edge"); break;
                      case 2 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE"); break;
                      case 3 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT INPUT POSITIVE Active Edge"); break;
                      case 4 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: HANDSHAKE OUTPUT"); break;
                      case 5 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: PULSE OUTPUT"); break;
                      case 6 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: LOW OUTPUT"); break;
                      case 7 : DEBUG_LOG(0,"PCR1: CB2 INTERRUPT CONTROL: HIGH OUTPUT"); break;
                    }


                    #endif




                    via[1].via[PCR]=xvalue; return;

		case IFR1 :                      /* IFR  */
            via[1].via[IFR] &= (0x7f^(xvalue & 0x7f));          // 1 writes to IFR are used to clear bits!
            if ( via[1].via[IFR] & 127) via[1].via[IFR]|=128;   // if all are cleared, clear bit 7 else set it
            else via[1].via[IFR]=0;

            DEBUG_LOG(0,"VIA1 IFR Write:%02x::%s %s %s %s %s %s %s %s\n",xvalue,
            (xvalue & VIA_IRQ_BIT_CA2        ) ? "CA2":"",
            (xvalue & VIA_IRQ_BIT_CA1        ) ? "CA1":"",
            (xvalue & VIA_IRQ_BIT_SR         ) ? "SR ":"",
            (xvalue & VIA_IRQ_BIT_CB2        ) ? "CB2":"",
            (xvalue & VIA_IRQ_BIT_CB1        ) ? "CB1":"",
            (xvalue & VIA_IRQ_BIT_T2         ) ? "T2 ":"",
            (xvalue & VIA_IRQ_BIT_T1         ) ? "T1 ":"",
            (xvalue & VIA_IRQ_BIT_SET_CLR_ANY) ? "ANY":"");

			return;

		case IER1 :
			/* IER  */
            DEBUG_LOG(0,"IER1");

              // if bit 7=0, then all 1 bits are reversed. 1=no irq, 0=irq enabled.
            if   (xvalue & 0x80)  via[1].via[IER] |= xvalue;
            else                  via[1].via[IER] &=(0x7f^( xvalue & 0x7f));

            DEBUG_LOG(0,"VIA1 IER Write:%02x::%s %s %s %s %s %s %s %s\n",xvalue,
            (xvalue & VIA_IRQ_BIT_CA2        ) ? "CA2":"",
            (xvalue & VIA_IRQ_BIT_CA1        ) ? "CA1":"",
            (xvalue & VIA_IRQ_BIT_SR         ) ? "SR ":"",
            (xvalue & VIA_IRQ_BIT_CB2        ) ? "CB2":"",
            (xvalue & VIA_IRQ_BIT_CB1        ) ? "CB1":"",
            (xvalue & VIA_IRQ_BIT_T2         ) ? "T2 ":"",
            (xvalue & VIA_IRQ_BIT_T1         ) ? "T1 ":"",
            (xvalue & VIA_IRQ_BIT_SET_CLR_ANY) ? "SET":"CLEAR");

            DEBUG_LOG(0,"VIA1 IER Value:%02x::%s %s %s %s %s %s %s %s\n",via[1].via[IER],
            (via[1].via[IER] & VIA_IRQ_BIT_CA2        ) ? "CA2":"",
            (via[1].via[IER] & VIA_IRQ_BIT_CA1        ) ? "CA1":"",
            (via[1].via[IER] & VIA_IRQ_BIT_SR         ) ? "SR ":"",
            (via[1].via[IER] & VIA_IRQ_BIT_CB2        ) ? "CB2":"",
            (via[1].via[IER] & VIA_IRQ_BIT_CB1        ) ? "CB1":"",
            (via[1].via[IER] & VIA_IRQ_BIT_T2         ) ? "T2 ":"",
            (via[1].via[IER] & VIA_IRQ_BIT_T1         ) ? "T1 ":"",
            (via[1].via[IER] & VIA_IRQ_BIT_SET_CLR_ANY) ? "SET":"CLEAR");

			return;
        default: DEBUG_LOG(0,"Illegal I/O addr Error %08x ignored (%02x not writen!)",addr,xvalue);
                 return;
	}
	return;
}


//lisa_rb_Oxdc00_cops_via1
uint8 lisa_rb_Oxdc00_cops_via1(uint32 addr)
{
    via[1].active=1;                        // these are always active as they're on the
    via[2].active=1;                        // motherboard of the machine...

    DEBUG_LOG(0,"reading from register %d (%s)", ((addr & 0x1f)>>1) ,via_regname(((addr & 0x1f)>>1) ));

    switch (addr & 0x1f)
	{
        case IRB1   : VIA_CLEAR_IRQ_PORT_B(1);
                      DEBUG_LOG(0,"IRB1");                                           //20060105 | for previously used outputs

                      via[1].via[IRBB]=via1_irb(0);    // read full byte into shadow

                      // now =        input shadow       input enabled bits       |  output shadow       output enabled bits
                      via[1].via[IRB]=(via[1].via[IRBB] & (0xff^via[1].via[DDRB])) | (via[1].via[ORBB] & via[1].via[DDRB]);

                      return via[1].via[IRB];


        case IRANH1 : VIA_CLEAR_IRQ_PORT_A(1);         //was ORANH1
                      via[1].last_a_accs=0;
                      DEBUG_LOG(0,"IRANH1");

                      via[1].via[IRAA]=via1_ira(15);   // read full byte into shadow

                      // now =        input shadow        input enabled bits       |  output shadow      output enabled bits
                      via[1].via[IRA]=(via[1].via[IRAA] & (0xff^via[1].via[DDRA])) | (via[1].via[ORAA] & via[1].via[DDRA]);

                      // if needed insert code to not do handshaking here
                      return via[1].via[IRA];

        case IRA1   : via[1].last_a_accs=0;
                      VIA_CLEAR_IRQ_PORT_A(1);
                      DEBUG_LOG(0,"IRA1");                                          //20060105 | previously used outputs

                      via[1].via[IRAA]=via1_ira(15);   // read full byte into shadow

                      // now =        input shadow        input enabled bits       |  output shadow      output enabled bits
                      via[1].via[IRA]=(via[1].via[IRAA] & (0xff^via[1].via[DDRA])) | (via[1].via[ORAA] & via[1].via[DDRA]);

                      return via[1].via[IRA];


        case DDRB1  : DEBUG_LOG(0,"DDRB1"); return via[1].via[DDRB];                       // DDRB
        case DDRA1  : DEBUG_LOG(0,"DDRA1"); return via[1].via[DDRA];                       //DDRA


		case T1LL1  :   // Timer 1 Low Order Latch
            DEBUG_LOG(0,"T1LL1");
            return (via[1].via[T1LL]);

		case T1LH1  :   // Time 1 High Order Latch
            DEBUG_LOG(0,"T1LH1");
            return via[1].via[T1LH];

		case T1CL1  :   // Timer 1 Low Order Counter
            DEBUG_LOG(0,"T1CL1");
            VIA_CLEAR_IRQ_T1(1);     // clear T1 irq on T1 read low or write high
            //via[1].via[T1CL]=get_via_timer_left_from_te(via[1].t1_e) & 0xff;

            via[1].via[T1CL]=get_via_timer_left_or_passed_from_te(via[1].t1_e,via[1].t1_set_cpuclk) & 0xff;
            return via[1].via[T1CL];

		case T1CH1  :  // Timer 1 High Order Counter
            DEBUG_LOG(0,"T1CH1");
            VIA_CLEAR_IRQ_T1(1);     // clear timer 1 interrupt on access
            via[1].via[T1CH]=get_via_timer_left_or_passed_from_te(via[1].t1_e,via[1].t1_set_cpuclk)>>8;
            return via[1].via[T1CH];

		case T2CL1  :  // Timer 2 Low Byte
            DEBUG_LOG(0,"read T2CL1 t2_e:%ld set at:%ld",via[1].t2_e, via[1].t2_set_cpuclk);

            via[1].via[T2CL]=get_via_timer_left_or_passed_from_te(via[1].t2_e,via[1].t2_set_cpuclk) & 0xff;

            //via[1].via[IFR] &=0xDF;                                    // clear T2 Interrupt from IFR  (bit 5) */
            VIA_CLEAR_IRQ_T2(1);                                        // clear T2 irq on T1 read low or write high

            return (via[1].via[T2CL]);

        case T2CH1  :
            DEBUG_LOG(0,"T2CH1");
            via[1].via[T2CH]=get_via_timer_left_or_passed_from_te(via[1].t2_e,via[1].t2_set_cpuclk)>>8;
            return via[1].via[T2CH];

        case SR1    : VIA_CLEAR_IRQ_SR(1);     // clear SR irq on SR access
                      DEBUG_LOG(0,"SR1");
                      return via[1].via[SHIFTREG];

        case ACR1   : DEBUG_LOG(0,"ACR1"); return via[1].via[ACR];
        case PCR1   : DEBUG_LOG(0,"PCR1"); return via[1].via[PCR];


        case IFR1   : DEBUG_LOG(0,"IFR COPS: SRC: copsqueuelen=%d",copsqueuelen);
                      // via1_ifr bit1 (2) is data in cops queue indicator

                      if (copsqueuelen>0 || (mousequeuelen>0 && cops_mouse>0))
                            via[1].via[IFR] |=2;
                      else  via[1].via[IFR] &=(253);

                      DEBUG_LOG(0,"COPS-IFR SRC: returning %02x, copsqueuelen:%d, mousequeuelen:%d",via[1].via[IFR],copsqueuelen,mousequeuelen);

                      if (pc24<0xfe0000)
                      DEBUG_LOG(0,"VIA1 IFR read:%02x at PC:%d/%08x::ifr0:%s ifr1:%s ifr2:%s ifr3:%s ifr4:%s ifr5:%s ifr6:%s ifr7:%s\n",via[1].via[IFR],context,pc24,
                      (via[1].via[IFR] & VIA_IRQ_BIT_CA2        ) ? "CA2:on":"CA2:off",
                      (via[1].via[IFR] & VIA_IRQ_BIT_CA1        ) ? "CA1:on":"CA1:off",
                      (via[1].via[IFR] & VIA_IRQ_BIT_SR         ) ? "SR :on":"SR :off",
                      (via[1].via[IFR] & VIA_IRQ_BIT_CB2        ) ? "CB2:on":"CB2:off",
                      (via[1].via[IFR] & VIA_IRQ_BIT_CB1        ) ? "CB1:on":"CB1:off",
                      (via[1].via[IFR] & VIA_IRQ_BIT_T2         ) ? "T2 :on":"T2 :off",
                      (via[1].via[IFR] & VIA_IRQ_BIT_T1         ) ? "T1 :on":"T1 :off",
                      (via[1].via[IFR] & VIA_IRQ_BIT_SET_CLR_ANY) ? "ANY:on":"ANY:off");

                      if (via[1].via[IER] & via[1].via[IFR] & 0x7f) via[1].via[IFR]|=128;  // bit 7 set if any data is in IFR

                      return via[1].via[IFR];

        case IER1   : DEBUG_LOG(0,"IER1");

                      if (pc24<0xfe0000)
                      DEBUG_LOG(0,"VIA1 IER read:%02x::ier0:%s ier1:%s ier2:%s ier3:%s ier4:%s ier5:%s ier6:%s ier7:%s\n",via[1].via[IFR],
                      (via[1].via[IER] & VIA_IRQ_BIT_CA2        ) ? "CA2:on":"CA2:off",
                      (via[1].via[IER] & VIA_IRQ_BIT_CA1        ) ? "CA1:on":"CA1:off",
                      (via[1].via[IER] & VIA_IRQ_BIT_SR         ) ? "SR :on":"SR :off",
                      (via[1].via[IER] & VIA_IRQ_BIT_CB2        ) ? "CB2:on":"CB2:off",
                      (via[1].via[IER] & VIA_IRQ_BIT_CB1        ) ? "CB1:on":"CB1:off",
                      (via[1].via[IER] & VIA_IRQ_BIT_T2         ) ? "T2 :on":"T2 :off",
                      (via[1].via[IER] & VIA_IRQ_BIT_T1         ) ? "T1 :on":"T1 :off",
                      (via[1].via[IER] & VIA_IRQ_BIT_SET_CLR_ANY) ? "ANY:on":"ANY:off");

                      via[1].via[IER] |= 0x80;  // docs says bit 7 is always logical 1
                      return via[1].via[IER];

        default: DEBUG_LOG(0,"Illegal addr error:%08x",addr);return 0xff;
	}
    return 0xff;
}


/*
* Contrast Control On PARALLEL PORT VIA!                                               *
*                                                                                      *
* Contrast Control Circuitry is located on the I/O board.  A d/a converter controls the*
* CRT display contrast, this is controlled by a latch connected to the Slow Data bus   *
* (hard disk interface 6522 peripheral port A.) To write a value to the contrast       *
* latch:  1. Set the DEN bit (PB2) to 1.  2. Put contrast $00-$FF in port A on the     *
* hard disk 6522.  3. Execute MOVE.L D0,$00D01C this causes a pulse on the contrast    *
* latch clock input.                                                                   *

                                                                                      *
* The address $00D01C in the I/O address space clears the clock input to the contrast  *
* latch.  The $00D01E sets the clock input so the MOVE instruction given above insures *
* that there is a positive edge on the clock input.                                    *

                                                                                      *
* When the system is reset either by the RESET instruction, or by a power-on, the      *
* contrast latch is reset and the screen is cleared.  The higher the number stored in  *
* the constrast latch, the higher the display contrast.                                *
*                                                                                      *
*
* should be 0xFCD01C for Contrast Latch...
*
*/




void lisa_wb_Oxd800_par_via2(uint32 addr, uint8 xvalue)
{

    via[1].active=1;                        // these are always active as they're on the
    via[2].active=1;                        // motherboard of the machine...

    DEBUG_LOG(0,"writing %02x to register %d (%s) @%08x", xvalue, (addr & 0x79)/8 ,via_regname((addr & 0x79)/8),addr );


    switch (addr & 0x79)  // fcd901      // was 0x7f it's now 0x79  // 2004.06.24 because saw MOVEP.W to T2CH, but suspect it also writes to T2CL!
	{
        case ORB2  :  //IRB/ORB
           {
            #ifdef DEBUG
             uint8 flipped=(via[2].via[ORBB] ^ xvalue) & via[2].via[DDRB];

             DEBUG_LOG(0,"Writing VIA2 ORB. DDRB mask=%02x:(%s%s%s%s%s%s%s%s)",via[2].via[DDRB],
                                ( (via[2].via[DDRB] &    1) ?"OCD:PB0:out ":"OCD:pb0:in  "),
                                ( (via[2].via[DDRB] &    2) ?"BSY:PB1:out ":"BSY:pb1:in  "),
                                ( (via[2].via[DDRB] &    4) ?"DEN:PB2:out ":"DEN:pb2:in  "),
                                ( (via[2].via[DDRB] &    8) ?"RRW:PB3:out ":"RRW:pb3:in  "),
                                ( (via[2].via[DDRB] &   16) ?"CMD:PB4:out ":"CMD:pb4:in  "),
                                ( (via[2].via[DDRB] &   32) ?"PAR:PB5:out ":"PAR:pb5:in  "),
                                ( (via[2].via[DDRB] &   64) ?"DSK:PB6:out ":"DSK:pb6:in  "),
                                ( (via[2].via[DDRB] &  128) ?"CRS:PB7:out ":"CRS:pb7:in  "));

             DEBUG_LOG(0,"ORB bits Flipped  :(%s%s%s%s%s%s%s%s)",
                                (( flipped &    1) ?"OCD:PB0 ":" "),
                                (( flipped &    2) ?"BSY:PB1 ":" "),
                                (( flipped &    4) ?"DEN:PB2 ":" "),
                                (( flipped &    8) ?"RRW:PB3 ":" "),
                                (( flipped &   16) ?"CMD:PB4 ":" "),
                                (( flipped &   32) ?"PAR:PB5 ":" "),
                                (( flipped &   64) ?"DSK:PB6 ":" "),
                                (( flipped &  128) ?"CRS:PB7 ":" "));

             if (flipped & 16) DEBUG_LOG(0,"profile.c: CMD Flipped to %d at PC24:%08x  tag:profile step:%d",xvalue&16,pc24,via[2].ProFile->StateMachineStep);

             DEBUG_LOG(0,"VIA2 ORB write=%02x:(OCD:%s BSY:%s DEN:%s RRW: %sCMD:%s PAR:%s DSKDIAG:%s CRES:%s)",xvalue,
                                (( xvalue &    1) ?"OCD:PB0:1 ":"OCD:PB0:0 "),
                                (( xvalue &    2) ?"BSY:PB1:1 ":"BSY:PB1:0 "),
                                (( xvalue &    4) ?"DEN:PB2:1 ":"DEN:PB2:0 "),
                                (( xvalue &    8) ?"RRW:PB3:1 ":"RRW:PB3:0 "),
                                (( xvalue &   16) ?"CMD:PB4:1 ":"CMD:PB4:0 "),
                                (( xvalue &   32) ?"PAR:PB5:1 ":"PAR:PB5:0 "),
                                (( xvalue &   64) ?"DSK:PB6:1 ":"DSK:PB6:0 "),
                                (( xvalue &  128) ?"CRS:PB7:1 ":"CRS:PB7:0 "));

            #endif

            via[2].via[ORBB]=xvalue; // set the shadow register to the unmasked data for later use.
            via[2].via[ORB]=(via[2].via[IRBB] & (~via[2].via[DDRB])) | (via[2].via[ORBB] & via[2].via[DDRB]);

            VIA_CLEAR_IRQ_PORT_B(2); // clear Cb1/Cb2 on ORb/IRb access

            if ( !via[2].via[DDRB]) return;  // don't write anything (no handshake) if the DDRB is all inputs
            via2_orb(via[2].via[ORBB] & via[2].via[DDRB]); // output the masked data.

			return;
            }
		case ORANH2 : //IRA/ORA
            DEBUG_LOG(0,"ORANH2");

            via[2].last_a_accs=1;
            if (via[2].ProFile) via[2].ProFile->last_a_accs=1;

            if (via[2].via[ORA]==xvalue)
            {
                    DEBUG_LOG(0,"ORANH2: Already wrote %02 to port, not pushing it",xvalue);
                    return;  // already what's on the port, ignore the write //20060418
            }
            via[2].via[ORAA]=xvalue;         // set the shadow register to the unmasked data for later use.
            via[2].via[ORA]=(via[2].via[IRAA] & (~via[2].via[DDRA])) | (via[2].via[ORAA] & via[2].via[DDRA]);

            if ( !via[2].via[DDRA]) {  // don't write anything if the DDRA is all inputs
                                       via[2].orapending=1;
                                       DEBUG_LOG(0,"ORANH: Not writing %02x now, but setting pending since DDRA=0",xvalue);
                                       return;
                                    }

            via2_ora(via[2].via[ORAA] & via[2].via[DDRA],15);
            //via[2].orapending=1;              //20060417//


			return;

        case ORA2   :
            DEBUG_LOG(0,"ORA2");
            via[2].last_a_accs=1;
            if (via[2].ProFile) via[2].ProFile->last_a_accs=1;
            VIA_CLEAR_IRQ_PORT_A(2); // clear CA1/CA2 on ORA/IRA access

            via[2].via[ORA]=(via[2].via[IRAA] & (~via[2].via[DDRA])) | (via[2].via[ORAA] & via[2].via[DDRA]);

            via[2].via[ORAA]= xvalue;

            if ( !via[2].via[DDRA]) {  // don't write anything if the DDRA is all inputs
                                       via[2].orapending=1;
                                       return;
                                    }

            via2_ora(via[2].via[ORAA] & via[2].via[DDRA],ORA); //output the masked data
            via[2].orapending=0;
			return;

		case DDRB2  :         // DDRB 2
            DEBUG_LOG(0,"DDRB2");
            via[2].via[DDRB]=xvalue;

            DEBUG_LOG(0,"Writing VIA2 DDRB mask=%02x:(%s%s%s%s%s%s%s%s)",via[2].via[DDRB],
                                ( (via[2].via[DDRB] &    1) ?"OCD:PB0:out ":"OCD:pb0:in  "),
                                ( (via[2].via[DDRB] &    2) ?"BSY:PB1:out ":"BSY:pb1:in  "),
                                ( (via[2].via[DDRB] &    4) ?"DEN:PB2:out ":"DEN:pb2:in  "),
                                ( (via[2].via[DDRB] &    8) ?"RRW:PB3:out ":"RRW:pb3:in  "),
                                ( (via[2].via[DDRB] &   16) ?"CMD:PB4:out ":"CMD:pb4:in  "),
                                ( (via[2].via[DDRB] &   32) ?"PAR:PB5:out ":"PAR:pb5:in  "),
                                ( (via[2].via[DDRB] &   64) ?"DSK:PB6:out ":"DSK:pb6:in  "),
                                ( (via[2].via[DDRB] &  128) ?"CRS:PB7:out ":"CRS:pb7:in  "));



            if ( xvalue  ) // only try the write if the mask has changed
                 via2_orb(via[2].via[ORBB] & via[2].via[DDRB]); // output the data that was masked off
            return;

		case DDRA2  :         // and DDRA 3 registers

             DEBUG_LOG(0,"Overwriting DDRA (previous value was=%02x, new value is:%02x)",
                          via[2].via[DDRA],xvalue);

             via[2].via[DDRA]=xvalue;

             DEBUG_LOG(0,"Wrote DDRA mask=%02x:(%s%s%s%s%s%s%s%s)",via[2].via[DDRA],
                                ( (via[2].via[DDRA] &    1) ?"PA0:out ":"pb0:in  "),
                                ( (via[2].via[DDRA] &    2) ?"PA1:out ":"pb1:in  "),
                                ( (via[2].via[DDRA] &    4) ?"PA2:out ":"pb2:in  "),
                                ( (via[2].via[DDRA] &    8) ?"PA3:out ":"pb3:in  "),
                                ( (via[2].via[DDRA] &   16) ?"PA4:out ":"pb4:in  "),
                                ( (via[2].via[DDRA] &   32) ?"PA5:out ":"pb5:in  "),
                                ( (via[2].via[DDRA] &   64) ?"PA6:out ":"pb6:in  "),
                                ( (via[2].via[DDRA] &  128) ?"PA7:out ":"pb7:in  "));




            if (via[2].orapending && xvalue!=0) // only try to write if this mask changed and last access to A was a write
                {
                  DEBUG_LOG(0,"via[2].orapending=%02x, DDRA=%02x, last write was:%02x",
                            via[2].orapending,
                            xvalue,
                            via[2].via[ORAA] );

                  via2_ora((via[2].via[ORAA] & xvalue), ORA); //output the masked data
                }
			return;

		case T1LL2  :   // Timer 1 Low Order Latch
            DEBUG_LOG(0,"T1LL2");

            via[2].via[T1CL]=xvalue;                                               // 4 T1LC actually writes to T1LL only
            via[2].via[T1LL]=xvalue;
            via[2].t1_e=get_via_te_from_timer((via[2].via[T1LH]<<8)|via[2].via[T1LL]);

            FIX_CLKSTOP_VIA_T1(2);      // update cpu68k_clocks_stop if needed

            //#ifdef DEBUG
            via[2].t1_set_cpuclk=cpu68k_clocks;
            //#endif
            via_running=1;
            DEBUG_LOG(0,"ll-t1clk:%d T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((via[2].via[T1LH]<<8)|via[2].via[T1LL]) , via[2].t1_e, via[2].t1_e-cpu68k_clocks,cpu68k_clocks);

            return;                        // Set timer2 low byte

		case T1LH2  :
            DEBUG_LOG(0,"T1LH2");
            via[2].via[T1LH]=(xvalue);                                             // Set timer1 latch and counter
            via_running=1;
            //2005.05.31 - this next line was disabled - should it have been?
            //via[1].t1_e=get_via_te_from_timer((via[1].via[T1LH]<<8)|via[1].via[T1LL]);
            // VIA_CLEAR_IRQ_T1(1);     // clear T1 irq on T1 read low or write high - does this clear the timer?

            DEBUG_LOG(0,"lh-t1clk:%d (%04x) t1lh1=%02x T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((via[2].via[T1LH]<<8)|via[2].via[T1LL]) ,
                    ((via[2].via[T1LH]<<8)|via[2].via[T1LL]) , xvalue,
                    via[2].t1_e,
                    via[2].t1_e-cpu68k_clocks,cpu68k_clocks);

            return;

		case T1CL2  :
            DEBUG_LOG(0,"T1CL2");

            via[2].via[T1LL]=xvalue;

            //via[2].t1_e=get_via_te_from_timer((via[2].via[T1LH]<<8)|via[1].via[T1LL]);   // so, does this still count down? likely not!
            //FIX_CLKSTOP_VIA_T1(1);      // update cpu68k_clocks_stop if needed           // disable this code here.
            // via[2].t1_set_cpuclk=cpu68k_clocks;

            via_running=1;

            DEBUG_LOG(0,"cl-t1clk:%d (%04x) CL1=%02x T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((via[2].via[T1LH]<<8)|via[2].via[T1LL]) ,
                    ((via[2].via[T1LH]<<8)|via[2].via[T1LL]) , xvalue,
                    via[2].t1_e, via[2].t1_e-cpu68k_clocks,cpu68k_clocks);
            return;


        case T1CH2  :
            DEBUG_LOG(0,"T1CH2");
            if ( via[2].via[ACR]&128) via[2].via[IRB] &= 0x7f;                             // with ACR7=1, a write to T1C brings PB7 low
            via[2].via[T1LH]=xvalue;                                                       // load into register
            via[2].via[T1CH]=via[2].via[T1LH]; via[2].via[T1CL]=via[2].via[T1LL];          // 5 T1HC actually writes to T1HL + copies T1LL->T1CL, T1LH->T1CH

            via[2].t1_e=get_via_te_from_timer((via[2].via[T1CH]<<8)|via[2].via[T1LL]);     // this one does tell the counter to count down!
            FIX_CLKSTOP_VIA_T1(2);                                                         // update cpu68k_clocks_stop if needed
            via[2].t1_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)

            VIA_CLEAR_IRQ_T1(2);     // clear T1 irq on T1 read low or write high

            DEBUG_LOG(0,"ch-t1clk:%d (%04x) CH1=%02x T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((via[2].via[T1LH]<<8)|via[2].via[T1LL]),
                    ((via[2].via[T1LH]<<8)|via[2].via[T1LL]), xvalue,
                    via[2].t1_e, via[2].t1_e-cpu68k_clocks,cpu68k_clocks);

            via_running=1;
            return;


        case T2CL2:  // Set Timer 2 Low Latch
            DEBUG_LOG(0,"T2CL2");
            via[2].via[T2LL]=xvalue;                                                       // Set t2 latch low
            //via[2].via[T2CL]=xvalue;                                                       // NOT SURE ABout this one!  2004.12.02
            // no change to the counter! only the latch! //2005.06.05
            // via[2].t2_e=get_via_te_from_timer((via[2].via[T2LH]<<8)|via[2].via[T2CL]);     // set timer expiration
            //FIX_CLKSTOP_VIA_T2(1);                                                         // update cpu68k_clocks_stop if needed
            //via[2].t2_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)


            //#ifdef DEBUG
            via[2].t2_set_cpuclk=cpu68k_clocks;
            DEBUG_LOG(0,"t2clk:%d (write takes effect on write to T2H) T2 set to expire at clock:%llx time now is %llx which is %llx cycles from now",
                    ((via[2].via[T2LH]<<8)|via[2].via[T2CL]),via[2].t2_e,cpu68k_clocks,via[2].t2_e-cpu68k_clocks);
            //#endif
            via_running=1;
            return;

        case T2CH2: // timer2 high byte
              // a write to T2H will load and the counter as well.
            DEBUG_LOG(0,"T2CH2");

            via[2].via[T2LH]=xvalue;                                                       // Set t2 latch high
            via[2].via[T2CH]=xvalue; via[2].via[T2CL]=via[2].via[T2LL];                    // load the counter with latches

            VIA_CLEAR_IRQ_T2(2);     // clear T2 irq on T2 read low or write high

            via[2].t2_e=get_via_te_from_timer((via[2].via[T2CH]<<8)|via[2].via[T2CL]);     // set timer expiration
            DEBUG_LOG(0,"via[2].t2_e=%ld",via[2].t2_e);
            FIX_CLKSTOP_VIA_T2(2);                                                         // update cpu68k_clocks_stop if needed
            via[2].t2_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)

            DEBUG_LOG(0,"t2clk:%d T2 set to expire at CPU clock:%llx time now is %llx which is %llx cycles from now.  stop is:%llx",
                    ((via[2].via[T2LH]<<8)|via[2].via[T2CL]),via[2].t2_e,cpu68k_clocks,via[2].t2_e-cpu68k_clocks,cpu68k_clocks_stop);

            via_running=1;

			return;


        case SR2:
            {
            //char srwrite[128];             //unused
            uint8 shift=(via[2].via[ACR] & 28)>>2;

            DEBUG_LOG(0,"Write %02x to shift register on VIA2!!!!",xvalue);
            //fprintf(buglog,"Write %02x to shift register on VIA2!!!!\n",xvalue);


           // #ifdef DEBUG
           // if (xvalue==0)  debug_off();
           // #endif


            // EXIT(53);

            DEBUG_LOG(0,"SR2");
            via[2].via[SHIFTREG]=xvalue;                     // write shift register
            via_running=1;
            via[2].srcount=0;

            // if (shift==4) {} - free running mode from T2 - timing tied to T2
            // if (shift==5) {} - one shot T2 mode - timing tied to T2
            if (shift==6)    {via[2].sr_e=cpu68k_clocks+VIACLK_TO_CPUCLK(8); get_next_timer_event();}
            ///if (shift==6)    {via[2].sr_e=cpu68k_clocks+8*via_clock_diff; get_next_timer_event();}
            //if (shift==7) - not implemented since CB1 is not connected on Lisa I/O board

            VIA_CLEAR_IRQ_SR(2);     // clear SR irq on SR access
            }
            return;

        case ACR2 :
                    DEBUG_LOG(0,"ACR2 Port A Latching:%s  Port B Latching:%s",
                    ((xvalue & BIT0) ?"Enabled":"Disabled"),
                    ((xvalue & BIT1) ?"Enabled":"Disabled")  );
                    #ifdef DEBUG
                    switch(xvalue & (BIT4|BIT3|BIT2)>>2)  {
                      case 0:        DEBUG_LOG(0,"ACR2 SHIFT REG DISABLED");                    break;
                      case 1:        DEBUG_LOG(0,"ACR2 SR SHIFT IN UNDER COMTROL OF T2");       break;
                      case 2:        DEBUG_LOG(0,"ACR2 SR SHIFT IN UNDER CONTROL OF 02");       break;
                      case 3:        DEBUG_LOG(0,"ACR2 SR SHIFT IN UNDER CONTROL OF EXT.CLK");  break;
                      case 4:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT FREE-RUNNING AT T2 RATE");  break;
                      case 5:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT UNDER CONTROL OF T2");      break;
                      case 6:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT UNDER CONTROL OF 02");      break;
                      case 7:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT UNDER CONTROL OF EXT.CLK"); break;
                    }

                    DEBUG_LOG(0,"ACR2 Timer2 Control: %s", ((xvalue & BIT6) ? "Countdown with PB6 Pulses":"Timed IRQ"));

                    switch(xvalue & (BIT7|BIT6)>>6)  {
                      case 0:        DEBUG_LOG(0,"ACR2 Timer1 Control: TIMED IRQ Each Time T1 Loaded, PB7 Output Disabled"); break;
                      case 1:        DEBUG_LOG(0,"ACR2 Timer1 Control: CONTINUOUS IRQ's, PB7 Output Disabled"); break;
                      case 2:        DEBUG_LOG(0,"ACR2 Timer1 Control: TIMED IRQ Each Time T1 is loaded, PB7 - One Shot Output"); break;
                      case 3:        DEBUG_LOG(0,"ACR2 Timer1 Control: Continous IRQ's, PB7: SQUARE WAVE OUTPUT"); break;
                    }
                    #endif
                    via[2].via[ACR]=xvalue; return;

        case PCR2 : DEBUG_LOG(0,"PCR2");
                    #ifdef DEBUG

                    if (xvalue & 0)  {DEBUG_LOG(0,"PCR2: CA1 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE");}
                    else             {DEBUG_LOG(0,"PCR2: CA1 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE");}

                    switch((xvalue & 15)>>1) {
                      case 0 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE"); break;
                      case 1 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT Input NEG. Active Edge"); break;
                      case 2 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE"); break;
                      case 3 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT INPUT POSITIVE Active Edge"); break;
                      case 4 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: HANDSHAKE OUTPUT"); break;
                      case 5 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: PULSE OUTPUT"); break;
                      case 6 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: LOW OUTPUT"); break;
                      case 7 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: HIGH OUTPUT"); break;
                    }
                    DEBUG_LOG(0,"PCR2: cb1 irq ctl:%s active edge",((xvalue & BIT4) ? "1:positive":"0:negative") );
                    switch((xvalue & (BIT7|BIT6|BIT5))>>5) {
                      case 0 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE"); break;
                      case 1 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT Input NEG. Active Edge"); break;
                      case 2 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE"); break;
                      case 3 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT INPUT POSITIVE Active Edge"); break;
                      case 4 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: HANDSHAKE OUTPUT"); break;
                      case 5 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: PULSE OUTPUT"); break;
                      case 6 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: LOW OUTPUT"); break;
                      case 7 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: HIGH OUTPUT"); break;
                    }
                   #endif
             if ((via[2].via[PCR] ^ xvalue) & 1) via[2].via[IFR]|=2;
             via[2].via[PCR]=xvalue; return;

		case IFR2 :                      /* IFR  */

            via[2].via[IFR]&=(0x7f^(xvalue & 0x7f));  // 1 writes to IFR are used to clear bits!
            if ( via[2].via[IFR] & 127) via[2].via[IFR]|=128;   // if all are cleared, clear bit 7 else set it
            else via[2].via[IFR]=0;

            DEBUG_LOG(0,"IFR2 write bits: %s %s %s %s %s %s %s %s",
                           (via[2].via[IFR] &   1) ? "ifr0CA2:on"              :"ifr0CA2:off",
                           (via[2].via[IFR] &   2) ? "bsy_ifr1CA1:on"          :"bsy_ifr1CA1:off",
                           (via[2].via[IFR] &   4) ? "ifr2SR :on"              :"ifr2SR :off",
                           (via[2].via[IFR] &   8) ? "parity_ifr3CB2:on"       :"parity_ifr3CB2:off",
                           (via[2].via[IFR] &  16) ? "not_connected_ifr4CB1:on":"not_connected_ifr4CB1:off",
                           (via[2].via[IFR] &  32) ? "ifr5T2 :on"              :"ifr5T2 :off",
                           (via[2].via[IFR] &  64) ? "ifr6T1 :on"              :"ifr6T1 :off",
                           (via[2].via[IFR] & 128) ? "ifr7ANY:on"              :"ifr7ANY:off");



			return;

        case IER2 :
            DEBUG_LOG(0,"IER2");
            //if bit 7=0, then all 1 bits are reversed. 1=no irq, 0=irq enabled.

            if  (xvalue & 0x80) via[2].via[IER] |=xvalue;
            else                via[2].via[IER] &=(0x7f^(xvalue&0x7f));


            // from via 1// if bit 7=0, then all 1 bits are reversed. 1=no irq, 0=irq enabled.
            ///if   (xvalue & 128) {via[1].via[IER] |= xvalue;}
            ///else via[1].via[IER] &=(0x7f-( xvalue & 0x7f));
            #ifdef DEBUG
            if (xvalue & 0x80)
               {
                DEBUG_LOG(0,"VIA2 IER Write Set:%02x::%s %s %s %s %s %s %s %s\n",xvalue,
                ((xvalue & VIA_IRQ_BIT_CA2        ) ? "CA2":""),
                ((xvalue & VIA_IRQ_BIT_CA1        ) ? "CA1":""),
                ((xvalue & VIA_IRQ_BIT_SR         ) ? "SR ":""),
                ((xvalue & VIA_IRQ_BIT_CB2        ) ? "CB2":""),
                ((xvalue & VIA_IRQ_BIT_CB1        ) ? "CB1":""),
                ((xvalue & VIA_IRQ_BIT_T2         ) ? "T2 ":""),
                ((xvalue & VIA_IRQ_BIT_T1         ) ? "T1 ":""),
                ((xvalue & VIA_IRQ_BIT_SET_CLR_ANY) ? "SET":"CLEAR"));
               }
            else
               {
               DEBUG_LOG(0,"VIA2 IER clear Value:%02x::%s %s %s %s %s %s %s %s\n",via[2].via[IER],
                ((via[2].via[IER] & VIA_IRQ_BIT_CA2        ) ? "CA2":""),
                ((via[2].via[IER] & VIA_IRQ_BIT_CA1        ) ? "CA1":""),
                ((via[2].via[IER] & VIA_IRQ_BIT_SR         ) ? "SR ":""),
                ((via[2].via[IER] & VIA_IRQ_BIT_CB2        ) ? "CB2":""),
                ((via[2].via[IER] & VIA_IRQ_BIT_CB1        ) ? "CB1":""),
                ((via[2].via[IER] & VIA_IRQ_BIT_T2         ) ? "T2 ":""),
                ((via[2].via[IER] & VIA_IRQ_BIT_T1         ) ? "T1 ":""),
                ((via[2].via[IER] & VIA_IRQ_BIT_SET_CLR_ANY) ? "SET":"CLEAR"));
               }
            #endif
			return;
        default: DEBUG_LOG(0,"Illegal address error Write to illegal address in via2_wb_ @ %08x",addr);
	}
	return;
}


uint8 lisa_rb_Oxd800_par_via2(uint32 addr)
{
    via[1].active=1;                        // these are always active as they're on the
    via[2].active=1;                        // motherboard of the machine...

    DEBUG_LOG(0,"reading from register %d (%s)", ((addr & 0x7f)>>3) ,via_regname(((addr & 0x7f)>>3) ));


    switch (addr & 0x79)                // was 7f, changing to 79
	{
        case IRB2   :
                    {
                     #ifdef DEBUG
                     uint8 flipped=via[2].via[IRBB];
                     #endif

                     DEBUG_LOG(0,"Reading VIA2 IRB. DDRB mask=%02x:(%s%s%s%s%s%s%s%s)",via[2].via[DDRB],
                                ( (via[2].via[DDRB] &    1) ?"OCD:PB0:out ":"OCD:pb0:in  "),
                                ( (via[2].via[DDRB] &    2) ?"BSY:PB1:out ":"BSY:pb1:in  "),
                                ( (via[2].via[DDRB] &    4) ?"DEN:PB2:out ":"DEN:pb2:in  "),
                                ( (via[2].via[DDRB] &    8) ?"RRW:PB3:out ":"RRW:pb3:in  "),
                                ( (via[2].via[DDRB] &   16) ?"CMD:PB4:out ":"CMD:pb4:in  "),
                                ( (via[2].via[DDRB] &   32) ?"PAR:PB5:out ":"PAR:pb5:in  "),
                                ( (via[2].via[DDRB] &   64) ?"DSK:PB6:out ":"DSK:pb6:in  "),
                                ( (via[2].via[DDRB] &  128) ?"CRS:PB7:out ":"CRS:pb7:in  "));

                      via[2].via[IRBB]=via2_irb();

                      DEBUG_LOG(0,"via2_irb() returned %02x",via[2].via[IRBB]);

                      via[2].via[IRB]=(via[2].via[IRBB] & (~via[2].via[DDRB])) | (via[2].via[ORBB] & via[2].via[DDRB]);

                      DEBUG_LOG(0,"returning irb & !DDRB is %02x",via[2].via[IRB]);

                      VIA_CLEAR_IRQ_PORT_B(2); // clear Cb1/Cb2 on ORb/IRb access

                      #ifdef DEBUG
                      flipped ^=via[2].via[IRB];
                      DEBUG_LOG(0,"IRB Flipped:(%s%s%s%s%s%s%s%s)",
                                (( flipped &    1) ?"OCD:PB0 ":" "),
                                (( flipped &    2) ?"BSY:PB1 ":" "),
                                (( flipped &    4) ?"DEN:PB2 ":" "),
                                (( flipped &    8) ?"RRW:PB3 ":" "),
                                (( flipped &   16) ?"CMD:PB4 ":" "),
                                (( flipped &   32) ?"PAR:PB5 ":" "),
                                (( flipped &   64) ?"DSK:PB6 ":" "),
                                (( flipped &  128) ?"CRS:PB7 ":" "));



                      DEBUG_LOG(0,"VIA2 IRB read=%02x:(OCD:%s BSY:%s DEN:%s RRW: %sCMD:%s PAR:%s DSKDIAG:%s CRES:%s)",via[2].via[IRB],
                                ( (via[2].via[IRB] &    1) ?"PB0:1 ":"pb0:0 "),
                                ( (via[2].via[IRB] &    2) ?"PB1:1 ":"pb1:0 "),
                                ( (via[2].via[IRB] &    4) ?"PB2:1 ":"pb2:0 "),
                                ( (via[2].via[IRB] &    8) ?"PB3:1 ":"pb3:0 "),
                                ( (via[2].via[IRB] &   16) ?"PB4:1 ":"pb4:0 "),
                                ( (via[2].via[IRB] &   32) ?"PB5:1 ":"pb5:0 "),
                                ( (via[2].via[IRB] &   64) ?"PB6:1 ":"pb6:0 "),
                                ( (via[2].via[IRB] &  128) ?"PB7:1 ":"pb7:0 "));

                      #endif
                      return via[2].via[IRB];

                      }

        case IRANH2 : via[2].last_a_accs=0;
                      if (via[2].ProFile) via[2].ProFile->last_a_accs=0;

                      DEBUG_LOG(0,"IRANH2");                                          //20060105 or in old outputs

                      via[2].via[IRAA]=(via2_ira(15));
                      via[2].via[IRA]=(via[2].via[IRAA] & (~via[2].via[DDRA])) | (via[2].via[ORAA] & via[2].via[DDRA]);  // read data from port base it on DDRA mask

                      return via[2].via[IRA];


        case IRA2   : via[2].last_a_accs=0;
                      if (via[2].ProFile) via[2].ProFile->last_a_accs=0;

                      DEBUG_LOG(0,"IRA2");

                      VIA_CLEAR_IRQ_PORT_A(2); // clear CA1/CA2 on ORA/IRA access

                      via[2].via[IRAA]=(via2_ira(15));
                      via[2].via[IRA]=(via[2].via[IRAA] & (~via[2].via[DDRA])) | (via[2].via[ORAA] & via[2].via[DDRA]);  // read data from port base it on DDRA mask

                      return via[2].via[IRA];


        case DDRB2  : DEBUG_LOG(0,"DDRB2"); return via[2].via[DDRB];                                          // DDRB
        case DDRA2  : DEBUG_LOG(0,"DDRA2"); return via[2].via[DDRA];                                          //DDRA


		case T1LL2  :   // Timer 1 Low Order Latch
            DEBUG_LOG(0,"T1LL2=%02x",(via[2].via[T1LL]));
            return (via[2].via[T1LL]);

		case T1LH2  :   // Time 1 High Order Latch
            DEBUG_LOG(0,"T1LH2 %02x",via[2].via[T1LH]);
            return via[2].via[T1LH];

		case T1CL2  :   // Timer 1 Low Order Counter
            DEBUG_LOG(0,"T1CL2");
            VIA_CLEAR_IRQ_T1(2);     // clear T1 irq on T1 read low or write high
            //via[2].via[T1CL]=get_via_timer_left_from_te(via[2].t1_e) & 0xff;

            via[2].via[T1CL]=get_via_timer_left_or_passed_from_te(via[2].t1_e,via[2].t1_set_cpuclk) & 0xff;
            return via[2].via[T1CL];

		case T1CH2  :  // Timer 1 High Order Counter
            DEBUG_LOG(0,"T1CH2");
            VIA_CLEAR_IRQ_T1(2);     // clear timer 1 interrupt on access
            via[2].via[T1CH]=get_via_timer_left_or_passed_from_te(via[2].t1_e,via[2].t1_set_cpuclk)>>8;
            return via[2].via[T1CH];

        case T2CL2  :  // Timer 2 Low Byte
            DEBUG_LOG(0,"read T2CL2 t2_e:%ld set at:%ld",via[2].t2_e, via[2].t2_set_cpuclk);

            via[2].via[T2CL]=get_via_timer_left_or_passed_from_te(via[2].t2_e,via[2].t2_set_cpuclk) & 0xff;

            //via[2].via[IFR] &=0xDF;                                    // clear T2 Interrupt from IFR  (bit 5) */
            VIA_CLEAR_IRQ_T2(2);                                        // clear T2 irq on T1 read low or write high

            return (via[2].via[T2CL]);

        case T2CH2  :
            DEBUG_LOG(0,"T2CH2");//return via[2].via[T2CH];
            via[2].via[T2CH]=get_via_timer_left_or_passed_from_te(via[2].t2_e,via[2].t2_set_cpuclk)>>8;
            return via[2].via[T2CH];

        case SR2    :
                    { //unused//uint8 shift=(via[2].via[ACR] & 28)>>2;
                      // set up an event to expire 8 VIA clock cycles after current time.
///2005.06.28///                      if (shift==2) {via[2].sr_e=cpu68k_clocks+VIACLK_TO_CPUCLK(8); get_next_timer_event();}
                      ///if (shift==2) {via[2].sr_e=cpu68k_clocks+8*via_clock_diff; get_next_timer_event();}
                      DEBUG_LOG(0,"SR2");
                      VIA_CLEAR_IRQ_SR(2);     // clear SR irq on SR access
                      return via[2].via[SHIFTREG];
                     }

        case ACR2   : DEBUG_LOG(0,"ACR2"); return via[2].via[ACR];
        case PCR2   : DEBUG_LOG(0,"PCR2"); return via[2].via[PCR];

        case IFR2   :
                      if (via[2].ProFile)
                      {

                        if ( via[2].ProFile->BSYLine) via[2].via[IFR] |=(    VIA_IRQ_BIT_CA1);
                        //20060526-bug here// else                          via[2].via[IFR] &=(255-VIA_IRQ_BIT_CA1);

                        //20060525// via[2].via[IFR]|=8; -- do not enable this.       // Parity Error=true
                         via[2].via[IFR] &=~8;            //20060525 - want this one  // Parity Error=false
                      }

                      via[2].via[IFR] &= (0xff-0x04);  // explicitly shut off SR bit.
                      if (via[2].via[IER] & via[2].via[IFR] & 0x7f) via[2].via[IFR] |=0x80; // if any actively on, bit 7 is on.

                      DEBUG_LOG(0,"IFR2=%02x",via[2].via[IFR]);

                      DEBUG_LOG(0,"IFR2 bits: %s %s %s %s %s %s %s %s",
                           (via[2].via[IFR] &   1) ? "ifr0CA2:on"              :"ifr0CA2:off",
                           (via[2].via[IFR] &   2) ? "bsy_ifr1CA1:on"          :"bsy_ifr1CA1:off",
                           (via[2].via[IFR] &   4) ? "ifr2SR :on"              :"ifr2SR :off",
                           (via[2].via[IFR] &   8) ? "parity_ifr3CB2:on"       :"parity_ifr3CB2:off",
                           (via[2].via[IFR] &  16) ? "not_connected_ifr4CB1:on":"not_connected_ifr4CB1:off",
                           (via[2].via[IFR] &  32) ? "ifr5T2 :on"              :"ifr5T2 :off",
                           (via[2].via[IFR] &  64) ? "ifr6T1 :on"              :"ifr6T1 :off",
                           (via[2].via[IFR] & 128) ? "ifr7ANY:on"              :"ifr7ANY:off");

                      return via[2].via[IFR];


        case IER2   : DEBUG_LOG(0,"IER2");
                              via[2].via[IER]  |= 0x80;  // docs says this returns logical 1 for bit 7 when read
                      return  via[2].via[IER];

        default:  DEBUG_LOG(0,"Illegal Address Access VIA2:%08x",addr);
	}
	return 0;
}




uint8 viaX_ira(viatype *V,uint8 regnum)
{
    VIA_CLEAR_IRQ_PORT_A(V->vianum); // clear CA1/CA2 on ORA/IRA access
    //if (debug_log_enabled) fdumpvia2(buglog);
    // driver enable is off, don't process ADMP/Profile data output - not sure if this is correct.

    if (V->via[ORBB] & V->via[DDRB] & 4) {DEBUG_LOG(0,"VIA:%d Returning Contrast",V->vianum); return contrast;}

    if (V->ProFile) // Is this a profile?
	{
        VIAProfileLoop(V->vianum,V->ProFile,PROLOOP_EV_IRA);
        V->via[IRA]=V->ProFile->VIA_PA;
        DEBUG_LOG(0,"VIA:%d profile.c:READ %02x from ProFile, pc24:%08x  tag:profile state:%d",V->vianum,V->via[IRA],pc24,V->ProFile->StateMachineStep);
        return V->via[IRA];
	}
    else if (V->ADMP) {DEBUG_LOG(0,"ADMP read from IRA"); return 0;} // ADMP doesn't return anything far as I know
    //else if (V->ira!=NULL) return viaX_ira(2,regnum); // Some other thing attached.

	return 0; // nothing attached, ignore.
}


void  viaX_ora(viatype *V,uint8 data, uint8 regnum)
{
    VIA_CLEAR_IRQ_PORT_A(2); // clear CA1/CA2 on ORA/IRA access


    DEBUG_LOG(0,"VIA:%D ORA:%02x DDRA:%02x   ORB:%02x DDRB:%0x",V->vianum,V->via[ORA],V->via[DDRA],V->via[ORB],V->via[DDRB]);
    if (V->via[DDRA]==0) return;    // can't write just yet, ignore.
    //if ( check_contrast_set()) return;


    if (V->via[ORBB] & V->via[DDRB] & 4) return;    // driver enable is off, don't process ADMP/Profile data output.
    V->orapending=0;

    //if (debug_log_enabled) fdumpvia2(buglog);
    if (V->ProFile) // Is this a profile?
	{
        DEBUG_LOG(0,"VIA:%d profile.c:Sending byte %02x from viaX_ora to ProFile code pc24:%08x tag:profile step:%d @%d",
                V->vianum,
                data,
                pc24,
                V->ProFile->StateMachineStep,V->ProFile->indexwrite);
        V->ProFile->VIA_PA=data;  V->via[ORA]=data; V->ProFile->last_a_accs=1; //20060323//
        VIAProfileLoop(V->vianum,V->ProFile,PROLOOP_EV_ORA);

        return;
	}

    if (V->ADMP) {
                   V->via[ORA]=data;
                   DEBUG_LOG(0,"Sending %02x to ADMP",data);
                   ImageWriterLoop(V->ADMP,data);
                   V->via[IRB]=2;
                   V->via[IFR]|=2;
                   return;
                 }
}



void viaX_orb(ViaType *V, uint8 data)
{
    #ifdef DEBUG
     uint8 flipped=((data^V->via[ORBB]) & (V->via[DDRB]) );
    #endif

    VIA_CLEAR_IRQ_PORT_B(V->vianum); // clear Cb1/Cb2 on ORb/IRb access

    // Setting Contrast - DEN is off, PB7 is used as Strobe.
    if ( check_contrast_set()) return;


    // Is there an attached ProFile device on this parallel port?
    if (V->ProFile){

    // Push the ORB bits to the ProFile flags. (OCD/BSY/DSKDiag/PARITY_BIT are inputs, so we don't do them, hence they're
    // commented out, but left in for the sake of completeness / being pendantic, fasict, totalitarian, etc.
    //------------------------------------------------------------------------------------------------------------------------------------
    //  if ( OCDLine_BIT & V->via[DDRB]) {V->ProFile->DENLine=(data & OCDLine_BIT) ? 0:1;}   //0 Ignored - hardwired input only line
    //  if ( BSYLine_BIT & V->via[DDRB]) {V->ProFile->BSYLine=(data & BSYLine_BIT) ? 0:1;}   //1 Ignored - hardwired input only line
        if ( DENLine_BIT & V->via[DDRB]) {V->ProFile->DENLine=(data & DENLine_BIT) ? 0:1;}   //2 DEN - drive enable....
        if ( RRWLine_BIT & V->via[DDRB]) {V->ProFile->RRWLine=(data & RRWLine_BIT) ? 0:1;}   //3 RRW is 1=write, 0=read from port
        if ( CMDLine_BIT & V->via[DDRB]) {V->ProFile->CMDLine=(data & CMDLine_BIT) ? 0:1;}   //4 CMD line
    //  if ( PARITY_BIT   & V->via[DDRB]) {V->ProFile->Parity=(data &  PARITY_BIT) ? 0:1;}   //5 Parity error bit is input
        if ( DSK_DIAG_BIT & V->via[DDRB]) {DEBUG_LOG(0,"VIA:%d Write to DSK_DIAG on viaX_orb!:%02x",V->vianum,data & DSK_DIAG_BIT);} // 6 Floppy Disk Diag is input

        // this is wrong, reet is on VIa1!
       // if ( CTRL_RES_BIT & V->via[DDRB]) {if ((data & CTRL_RES_BIT)==0)                         //7 Controller reset
       //                                           { DEBUG_LOG(0,"Sent Controller Reset to ProFile:%02x",data & CTRL_RES_BIT);
       //                                             ProfileReset(V->ProFile);
       //                                           }
       //                                       }

        DEBUG_LOG(0,"VIA:%d profile.c:ORA:%02x DDRA:%02x   ORB:%02x DDRB:%0x",V->vianum,V->via[ORA],V->via[DDRA],V->via[ORB],V->via[DDRB]);
        DEBUG_LOG(0,"VIA:%d profile.c:pb0:!OCD:%d pb1:!BSY:%d pb2:!DEN:%d pb3:!DR/W/:%d pb4:!CMD/:%d pb5:PRES:%d pb6:DIAGWait:%d pb7:CTRL_RES:%d = Data=%02x",
                    V->vianum,
                    (data&1),(data&2),(data&4),(data&8),(data&16),(data&32),(data&64),(data&128),data);

        DEBUG_LOG(0,"Flipped bits: %s%s%s%s%s%s%s%s",((flipped &    1) ? "OCD:pb0 ":"    ")
                                                   , ((flipped &    2) ? "BSY:pb1 ":"    ")
                                                   , ((flipped &    4) ? "DEN:pb2 ":"    ")
                                                   , ((flipped &    8) ? "RRW:pb3 ":"    ")
                                                   , ((flipped &   16) ? "CMD:pb4 ":"    ")
                                                   , ((flipped &   32) ? "PAR:pb5 ":"    ")
                                                   , ((flipped &   64) ? "DSK:pb6 ":"    ")
                                                   , ((flipped &  128) ? "CRS:pb7 ":"    ") );


        V->ca1=V->ProFile->BSYLine; // refresh


        DEBUG_LOG(0,"before Lines DEN:%d RRW:%d CMD:%d",
                V->ProFile->DENLine,V->ProFile->RRWLine,V->ProFile->CMDLine);


 //       if (pc24<0x00fe0000) print_via_profile_state("\nviaX_orb pre-loop ", data,&via[2]);
 //       if (debug_log_enabled) fdumpvia2(buglog);
        VIAProfileLoop(V->vianum,V->ProFile,PROLOOP_EV_ORB);



        if (pc24<0x00fe0000) print_via_profile_state("\nviaX_orb post-loop ", data,&via[2]);

    if (0x80 & via[1].via[DDRB])
        {
            DEBUG_LOG(0,"VIA:%d via1_orb ProFile !RESET :%02x %02x (0 means no reset, 80 means reset)\n",V->vianum,data,data & 0x80); //20051214 flipped
            if (  ( (data & 0x80)) && V->ProFile) ProfileReset(V->ProFile);
        }  // PB7 = reset Profile


    }



    // Is there an attached dot matrix printer?
    if (V->ADMP)
    {
        DEBUG_LOG(0,"ADMP VIA:%d profile.c:pb0:!OCD:%d pb1:!BSY:%d pb2:!DEN:%d pb3:!DR/W/:%d pb4:!CMD/:%d pb5:PRES:%d pb6:DIAGWait:%d pb7:CTRL_RES:%d = Data=%02x",
                    V->vianum,
                    (data&1),(data&2),(data&4),(data&8),(data&16),(data&32),(data&64),(data&128),data);


            return;       // Output to Apple Dot Matrix Printer -- not yet implemented
    }
	return; // nothing attached, ignore.
}




uint8 viaX_irb(viatype *V) //this is good
{
    // remove these two.
    //static uint32 lastpc;
    //static uint32 lastpccount;

    uint8 retval=0;

     //floppy_6504_wait=!floppy_6504_wait;

     VIA_CLEAR_IRQ_PORT_B(V->vianum); // clear Cb1/Cb2 on ORb/IRb access

     // return the values of the previous output bits
     ///retval = V->via[IRB] & V->via[DDRB];  //20060110 - no longer needed

     if (floppy_ram[0]) {floppy_go6504();}  // if this is being read, it's likely Lisa is waiting on floppy, so speed it up

     // set up the return of the common bits before we deal with attached devices
     retval |= (floppy_6504_wait  ? 0:DSK_DIAG_BIT);  // return floppy diag bit
     retval |= (  ((V->ProFile||V->ADMP) && floppy_picked && powerfile_power) ? 0 : OCDLine_BIT);  // ADMP/Profile attached?

     if (V->ADMP)
           {
             DEBUG_LOG(0,"ADMP VIA#%d polled for IRB",V->vianum);
             retval=V->via[IRB];
             V->via[IRB]=0;
             return retval;

             //retval=  BSYLine_BIT;
             //return retval; // ADMP doesn't return anything far as I know
           }



   // Is there a ProFile on VIA2? - yes, some lines are crossed between VIA1 and VIA2 - likely a legacy design bug before ProFiles
   if (V->ProFile)
   {

      retval &=~32;
      retval |=(eparity[V->ProFile->VIA_PA] ? 32:0);  // was V->via[ORA]

      if (retval & 128) retval |=32;                        // when PB7=1 means ProFile is being reset, LisaTest expects PB5=1 too

      DEBUG_LOG(0,"VIA:%d Last ORA:%02x - Parity:%02x, DDRB:%d returning:%d",V->vianum,
                   V->via[ORA],
                   !eparity[V->via[ORA]],
                   (via[1].via[DDRB] & 32),
                   retval & 32);

      //if ((V->via[DDRB] & PARITY_BIT)==0) retval|=(eparity[V->via[ORA]] ? PARITY_BIT:0);
   }
   else DEBUG_LOG(0,"No Profile attached to Parallel Port!");



     if (V->ProFile){

        if (pc24<0x00fe0000) print_via_profile_state("\nviaX_irb pre-loop ", V->via[IRB],V);

        // BSY is controlled by the profile, while DEN, RRW, and CMD are controlled by Lisa.  Lisa bits must be set before
        // entering the ProFile loop - and they are from viaX_orb, while BSY must be set after the call to ProFile loop,
        // however, we set the rest of the bits in retval to return them to the Lisa as expected and to verify correctness.

        VIAProfileLoop(V->vianum,V->ProFile,PROLOOP_EV_IRB); // 2 means type of access, not VIA#

        // update return values from ProFile handshake/comm bits
        V->ca1=V->ProFile->BSYLine;

        // Next four lines do the same thing as their uncommented versions below.  Leaving commented version in for clarity.
        //if (!(V->via[DDRB] & BSYLine_BIT)) retval |= (V->ProFile->BSYLine ? 0 : BSYLine_BIT); else retval |=(V->via[IRB] & BSYLine_BIT);
        //if (!(V->via[DDRB] & DENLine_BIT)) retval |= (V->ProFile->DENLine ? 0 : DENLine_BIT); else retval |=(V->via[IRB] & DENLine_BIT);
        //if (!(V->via[DDRB] & RRWLine_BIT)) retval |= (V->ProFile->RRWLine ? 0 : RRWLine_BIT); else retval |=(V->via[IRB] & RRWLine_BIT);
        //if (!(V->via[DDRB] & CMDLine_BIT)) retval |= (V->ProFile->CMDLine ? 0 : CMDLine_BIT); else retval |=(V->via[IRB] & CMDLine_BIT);

        // If the DDRB bit is an input return the value sent by the profile, otherwise return the previous value of that bit from the old IRB
        retval |= (!(V->via[DDRB] & BSYLine_BIT)) ? (V->ProFile->BSYLine ? 0 : BSYLine_BIT) : (V->via[IRB] & BSYLine_BIT);
        retval |= (!(V->via[DDRB] & DENLine_BIT)) ? (V->ProFile->DENLine ? 0 : DENLine_BIT) : (V->via[IRB] & DENLine_BIT);
        retval |= (!(V->via[DDRB] & RRWLine_BIT)) ? (V->ProFile->RRWLine ? 0 : RRWLine_BIT) : (V->via[IRB] & RRWLine_BIT);
        retval |= (!(V->via[DDRB] & CMDLine_BIT)) ? (V->ProFile->CMDLine ? 0 : CMDLine_BIT) : (V->via[IRB] & CMDLine_BIT);


        if ((V->via[DDRB] & PARITY_BIT)==0) retval|=(eparity[V->via[ORA]] ? PARITY_BIT:0);  // re-enabled 2006.05.24
      //  if ((V->via[DDRB] & PARITY_BIT)==0) retval|=(eparity[V->via[ORA]] ? 0:PARITY_BIT);  // re-enabled 2006.05.25


        if (pc24<0x00fe0000) print_via_profile_state("\nviaX_irb post-loop ", retval,V);

        ///////////////////////////////////////////////////////////
        DEBUG_LOG(0,"VIA:%d Returning: %02x from viaX_irb ProFile code",V->vianum,retval);
        DEBUG_LOG(0,"VIA:%d profile.c:ORA:%02x DDRA:%02x   ORB:%02x DDRB:%0x",V->vianum,V->via[ORA],V->via[DDRA],V->via[ORB],V->via[DDRB]);
        V->via[IRB]=retval;    return retval;
     }
     //else
     //       return V->via[IRB];

    //retval |=0x02;   // Set ProFile busy line, since there isn't once attached.
    //retval |=4;      // Set Disk Enable Line to no drive there.

     DEBUG_LOG(0,"VIA:%d profile.c:pb0:!OCD:%d pb1:!BSY:%d pb2:!DEN:%d pb3:DR/W/:%d pb4:!CMD/:%d pb5:!PRES:%d pb6:DIAGWait:%d pb7:CTRL_RES:%d = Data=%02x",
                    V->vianum,
                    (retval&1),(retval&2),(retval&4),(retval&8),(retval&16),(retval&32),(retval&64),(retval&128),retval);


     //if (debug_log_enabled) fdumpvia2(buglog);
     V->via[IRB]=retval;    return retval;
}



uint8 lisa_rb_ext_2par_via(ViaType *V,uint32 addr)
{
    via[1].active=1;                     // these are always active as they're on the
    via[2].active=1;                     // these are always active as they're on the
    V->active=1;                        // motherboard of the machine...

    DEBUG_LOG(0,"VIA:%d reading from register %d (%s)", V->vianum,((addr & 0x7f)>>3) ,via_regname(((addr & 0x7f)>>3) ));


    switch (addr & 0x79)                // was 7f, changing to 79
	{
        case IRB2   :
                    {
                     #ifdef DEBUG
                     uint8 flipped=V->via[IRBB];
                     #endif

                     DEBUG_LOG(0,"Reading VIA2 IRB. DDRB mask=%02x:(%s%s%s%s%s%s%s%s)",V->via[DDRB],
                                ( (V->via[DDRB] &    1) ?"OCD:PB0:out ":"OCD:pb0:in  "),
                                ( (V->via[DDRB] &    2) ?"BSY:PB1:out ":"BSY:pb1:in  "),
                                ( (V->via[DDRB] &    4) ?"DEN:PB2:out ":"DEN:pb2:in  "),
                                ( (V->via[DDRB] &    8) ?"RRW:PB3:out ":"RRW:pb3:in  "),
                                ( (V->via[DDRB] &   16) ?"CMD:PB4:out ":"CMD:pb4:in  "),
                                ( (V->via[DDRB] &   32) ?"PAR:PB5:out ":"PAR:pb5:in  "),
                                ( (V->via[DDRB] &   64) ?"DSK:PB6:out ":"DSK:pb6:in  "),
                                ( (V->via[DDRB] &  128) ?"CRS:PB7:out ":"CRS:pb7:in  "));

                      V->via[IRBB]=viaX_irb(V);

                      DEBUG_LOG(0,"viaX_irb() returned %02x",V->via[IRBB]);

                      V->via[IRB]=(V->via[IRBB] & (~V->via[DDRB])) | (V->via[ORBB] & V->via[DDRB]);

                      DEBUG_LOG(0,"returning irb & !DDRB is %02x",V->via[IRB]);

                      VIA_CLEAR_IRQ_PORT_B(V->vianum); // clear Cb1/Cb2 on ORb/IRb access

                      #ifdef DEBUG
                      flipped ^=V->via[IRB];
                      DEBUG_LOG(0,"IRB Flipped:(%s%s%s%s%s%s%s%s)",
                                (( flipped &    1) ?"OCD:PB0 ":" "),
                                (( flipped &    2) ?"BSY:PB1 ":" "),
                                (( flipped &    4) ?"DEN:PB2 ":" "),
                                (( flipped &    8) ?"RRW:PB3 ":" "),
                                (( flipped &   16) ?"CMD:PB4 ":" "),
                                (( flipped &   32) ?"PAR:PB5 ":" "),
                                (( flipped &   64) ?"DSK:PB6 ":" "),
                                (( flipped &  128) ?"CRS:PB7 ":" "));



                      DEBUG_LOG(0,"VIA2 IRB read=%02x:(OCD:%s BSY:%s DEN:%s RRW: %sCMD:%s PAR:%s DSKDIAG:%s CRES:%s)",V->via[IRB],
                                ( (V->via[IRB] &    1) ?"PB0:1 ":"pb0:0 "),
                                ( (V->via[IRB] &    2) ?"PB1:1 ":"pb1:0 "),
                                ( (V->via[IRB] &    4) ?"PB2:1 ":"pb2:0 "),
                                ( (V->via[IRB] &    8) ?"PB3:1 ":"pb3:0 "),
                                ( (V->via[IRB] &   16) ?"PB4:1 ":"pb4:0 "),
                                ( (V->via[IRB] &   32) ?"PB5:1 ":"pb5:0 "),
                                ( (V->via[IRB] &   64) ?"PB6:1 ":"pb6:0 "),
                                ( (V->via[IRB] &  128) ?"PB7:1 ":"pb7:0 "));

                      #endif
                      return V->via[IRB];

                      }

        case IRANH2 : V->last_a_accs=0;
                      if (V->ProFile) V->ProFile->last_a_accs=0;

                      DEBUG_LOG(0,"IRANH");                                          //20060105 or in old outputs

                      V->via[IRAA]=(viaX_ira(V,15));
                      V->via[IRA]=(V->via[IRAA] & (~V->via[DDRA])) | (V->via[ORAA] & V->via[DDRA]);  // read data from port base it on DDRA mask

                      return V->via[IRA];


        case IRA2   : V->last_a_accs=0;
                      if (V->ProFile) V->ProFile->last_a_accs=0;

                      DEBUG_LOG(0,"IRA");

                      VIA_CLEAR_IRQ_PORT_A(V->vianum); // clear CA1/CA2 on ORA/IRA access

                      V->via[IRAA]=(viaX_ira(V,15));
                      V->via[IRA]=(V->via[IRAA] & (~V->via[DDRA])) | (V->via[ORAA] & V->via[DDRA]);  // read data from port base it on DDRA mask

                      return V->via[IRA];


        case DDRB2  : DEBUG_LOG(0,"DDRB"); return V->via[DDRB];                                          // DDRB
        case DDRA2  : DEBUG_LOG(0,"DDRA"); return V->via[DDRA];                                          //DDRA


		case T1LL2  :   // Timer 1 Low Order Latch
            DEBUG_LOG(0,"T1LL2=%02x",(V->via[T1LL]));
            return (V->via[T1LL]);

		case T1LH2  :   // Time 1 High Order Latch
            DEBUG_LOG(0,"T1LH2 %02x",V->via[T1LH]);
            return V->via[T1LH];

		case T1CL2  :   // Timer 1 Low Order Counter
            DEBUG_LOG(0,"T1CL2");
            VIA_CLEAR_IRQ_T1(V->vianum);     // clear T1 irq on T1 read low or write high
            //V->via[T1CL]=get_via_timer_left_from_te(V->t1_e) & 0xff;

            V->via[T1CL]=get_via_timer_left_or_passed_from_te(V->t1_e,V->t1_set_cpuclk) & 0xff;
            return V->via[T1CL];

		case T1CH2  :  // Timer 1 High Order Counter
            DEBUG_LOG(0,"T1CH2");
            VIA_CLEAR_IRQ_T1(V->vianum);     // clear timer 1 interrupt on access
            V->via[T1CH]=get_via_timer_left_or_passed_from_te(V->t1_e,V->t1_set_cpuclk)>>8;
            return V->via[T1CH];

        case T2CL2  :  // Timer 2 Low Byte
            DEBUG_LOG(0,"read T2CL2 t2_e:%ld set at:%ld",V->t2_e, V->t2_set_cpuclk);

            V->via[T2CL]=get_via_timer_left_or_passed_from_te(V->t2_e,V->t2_set_cpuclk) & 0xff;

            //V->via[IFR] &=0xDF;                                    // clear T2 Interrupt from IFR  (bit 5) */
            VIA_CLEAR_IRQ_T2(V->vianum);                                        // clear T2 irq on T1 read low or write high

            return (V->via[T2CL]);

        case T2CH2  :
            DEBUG_LOG(0,"T2CH2");//return V->via[T2CH];
            V->via[T2CH]=get_via_timer_left_or_passed_from_te(V->t2_e,V->t2_set_cpuclk)>>8;
            return V->via[T2CH];

        case SR2    :
                    { //unused//uint8 shift=(V->via[ACR] & 28)>>2;
                      // set up an event to expire 8 VIA clock cycles after current time.
///2005.06.28///                      if (shift==2) {V->sr_e=cpu68k_clocks+VIACLK_TO_CPUCLK(8); get_next_timer_event();}
                      ///if (shift==2) {V->sr_e=cpu68k_clocks+8*via_clock_diff; get_next_timer_event();}
                      DEBUG_LOG(0,"SR");
                      VIA_CLEAR_IRQ_SR(V->vianum);     // clear SR irq on SR access
                      return V->via[SHIFTREG];
                     }

        case ACR2   : DEBUG_LOG(0,"ACR"); return V->via[ACR];
        case PCR2   : DEBUG_LOG(0,"PCR"); return V->via[PCR];

        case IFR2   :
                      if (V->ProFile)
                      {

                        if ( V->ProFile->BSYLine) V->via[IFR] |=(    VIA_IRQ_BIT_CA1);
                        //20060526-bug here// else                          V->via[IFR] &=(255-VIA_IRQ_BIT_CA1);

                        //20060525// V->via[IFR]|=8; -- do not enable this.       // Parity Error=true
                         V->via[IFR] &=~8;            //20060525 - want this one  // Parity Error=false
                      }

                      V->via[IFR] &= (0xff-0x04);  // explicitly shut off SR bit.
                      if (V->via[IER] & V->via[IFR] & 0x7f) V->via[IFR] |=0x80; // if any actively on, bit 7 is on.

                      DEBUG_LOG(0,"IFR2=%02x",V->via[IFR]);

                      DEBUG_LOG(0,"IFR2 bits: %s %s %s %s %s %s %s %s",
                           (V->via[IFR] &   1) ? "ifr0CA2:on"              :"ifr0CA2:off",
                           (V->via[IFR] &   2) ? "bsy_ifr1CA1:on"          :"bsy_ifr1CA1:off",
                           (V->via[IFR] &   4) ? "ifr2SR :on"              :"ifr2SR :off",
                           (V->via[IFR] &   8) ? "parity_ifr3CB2:on"       :"parity_ifr3CB2:off",
                           (V->via[IFR] &  16) ? "not_connected_ifr4CB1:on":"not_connected_ifr4CB1:off",
                           (V->via[IFR] &  32) ? "ifr5T2 :on"              :"ifr5T2 :off",
                           (V->via[IFR] &  64) ? "ifr6T1 :on"              :"ifr6T1 :off",
                           (V->via[IFR] & 128) ? "ifr7ANY:on"              :"ifr7ANY:off");

                      return V->via[IFR];


        case IER2   : DEBUG_LOG(0,"IER2");
                              V->via[IER]  |= 0x80;  // docs says this returns logical 1 for bit 7 when read
                      return  V->via[IER];

        default:  DEBUG_LOG(0,"Illegal Address Access VIA2:%08x",addr);
	}
	return 0;
}

void lisa_wb_ext_2par_via(ViaType *V,uint32 addr, uint8 xvalue)
{

    via[1].active=1;                        // these are always active as they're on the
    V->active=1;                        // motherboard of the machine...

    DEBUG_LOG(0,"VIA:%d writing %02x to register %d (%s) @%08x", V->vianum,xvalue, (addr & 0x79)/8 ,via_regname((addr & 0x79)/8),addr );


    switch (addr & 0x79)  // fcd901      // was 0x7f it's now 0x79  // 2004.06.24 because saw MOVEP.W to T2CH, but suspect it also writes to T2CL!
	{
        case ORB2  :  //IRB/ORB
           {
            #ifdef DEBUG
             uint8 flipped=(V->via[ORBB] ^ xvalue) & V->via[DDRB];

             DEBUG_LOG(0,"Writing VIA2 ORB. DDRB mask=%02x:(%s%s%s%s%s%s%s%s)",V->via[DDRB],
                                ( (V->via[DDRB] &    1) ?"OCD:PB0:out ":"OCD:pb0:in  "),
                                ( (V->via[DDRB] &    2) ?"BSY:PB1:out ":"BSY:pb1:in  "),
                                ( (V->via[DDRB] &    4) ?"DEN:PB2:out ":"DEN:pb2:in  "),
                                ( (V->via[DDRB] &    8) ?"RRW:PB3:out ":"RRW:pb3:in  "),
                                ( (V->via[DDRB] &   16) ?"CMD:PB4:out ":"CMD:pb4:in  "),
                                ( (V->via[DDRB] &   32) ?"PAR:PB5:out ":"PAR:pb5:in  "),
                                ( (V->via[DDRB] &   64) ?"DSK:PB6:out ":"DSK:pb6:in  "),
                                ( (V->via[DDRB] &  128) ?"CRS:PB7:out ":"CRS:pb7:in  "));

             DEBUG_LOG(0,"ORB bits Flipped  :(%s%s%s%s%s%s%s%s)",
                                (( flipped &    1) ?"OCD:PB0 ":" "),
                                (( flipped &    2) ?"BSY:PB1 ":" "),
                                (( flipped &    4) ?"DEN:PB2 ":" "),
                                (( flipped &    8) ?"RRW:PB3 ":" "),
                                (( flipped &   16) ?"CMD:PB4 ":" "),
                                (( flipped &   32) ?"PAR:PB5 ":" "),
                                (( flipped &   64) ?"DSK:PB6 ":" "),
                                (( flipped &  128) ?"CRS:PB7 ":" "));

             if (flipped & 16) DEBUG_LOG(0,"profile.c: CMD Flipped to %d at PC24:%08x  tag:profile step:%d",xvalue&16,pc24,
                              (V->ProFile!=NULL) ? (V->ProFile->StateMachineStep):-99);

             DEBUG_LOG(0,"VIA2 ORB write=%02x:(OCD:%s BSY:%s DEN:%s RRW: %sCMD:%s PAR:%s DSKDIAG:%s CRES:%s)",xvalue,
                                (( xvalue &    1) ?"OCD:PB0:1 ":"OCD:PB0:0 "),
                                (( xvalue &    2) ?"BSY:PB1:1 ":"BSY:PB1:0 "),
                                (( xvalue &    4) ?"DEN:PB2:1 ":"DEN:PB2:0 "),
                                (( xvalue &    8) ?"RRW:PB3:1 ":"RRW:PB3:0 "),
                                (( xvalue &   16) ?"CMD:PB4:1 ":"CMD:PB4:0 "),
                                (( xvalue &   32) ?"PAR:PB5:1 ":"PAR:PB5:0 "),
                                (( xvalue &   64) ?"DSK:PB6:1 ":"DSK:PB6:0 "),
                                (( xvalue &  128) ?"CRS:PB7:1 ":"CRS:PB7:0 "));

            #endif

            V->via[ORBB]=xvalue; // set the shadow register to the unmasked data for later use.
            V->via[ORB]=(V->via[IRBB] & (~V->via[DDRB])) | (V->via[ORBB] & V->via[DDRB]);

            VIA_CLEAR_IRQ_PORT_B(V->vianum); // clear Cb1/Cb2 on ORb/IRb access

            if ( !V->via[DDRB]) return;  // don't write anything (no handshake) if the DDRB is all inputs
            viaX_orb(V,V->via[ORBB] & V->via[DDRB]); // output the masked data.

			return;
            }
		case ORANH2 : //IRA/ORA
            DEBUG_LOG(0,"ORANH");

            V->last_a_accs=1;
            if (V->ProFile) V->ProFile->last_a_accs=1;

            if (V->via[ORA]==xvalue)
            {
                    DEBUG_LOG(0,"ORANH2: Already wrote %02 to port, not pushing it",xvalue);
                    return;  // already what's on the port, ignore the write //20060418
            }
            V->via[ORAA]=xvalue;         // set the shadow register to the unmasked data for later use.
            V->via[ORA]=(V->via[IRAA] & (~V->via[DDRA])) | (V->via[ORAA] & V->via[DDRA]);

            if ( !V->via[DDRA]) {  // don't write anything if the DDRA is all inputs
                                       V->orapending=1;
                                       DEBUG_LOG(0,"ORANH: Not writing %02x now, but setting pending since DDRA=0",xvalue);
                                       return;
                                    }

            viaX_ora(V,V->via[ORAA] & V->via[DDRA],15);
            //V->orapending=1;              //20060417//


			return;

        case ORA2   :
            DEBUG_LOG(0,"ORA");
            V->last_a_accs=1;
            if (V->ProFile) V->ProFile->last_a_accs=1;
            VIA_CLEAR_IRQ_PORT_A(V->vianum); // clear CA1/CA2 on ORA/IRA access

            V->via[ORA]=(V->via[IRAA] & (~V->via[DDRA])) | (V->via[ORAA] & V->via[DDRA]);

            V->via[ORAA]= xvalue;

            if ( !V->via[DDRA]) {  // don't write anything if the DDRA is all inputs
                                       V->orapending=1;
                                       return;
                                    }

            viaX_ora(V,V->via[ORAA] & V->via[DDRA],ORA); //output the masked data
            V->orapending=0;
			return;

		case DDRB2  :         // DDRB 2
            DEBUG_LOG(0,"DDRB2");
            V->via[DDRB]=xvalue;

            DEBUG_LOG(0,"Writing VIA2 DDRB mask=%02x:(%s%s%s%s%s%s%s%s)",V->via[DDRB],
                                ( (V->via[DDRB] &    1) ?"OCD:PB0:out ":"OCD:pb0:in  "),
                                ( (V->via[DDRB] &    2) ?"BSY:PB1:out ":"BSY:pb1:in  "),
                                ( (V->via[DDRB] &    4) ?"DEN:PB2:out ":"DEN:pb2:in  "),
                                ( (V->via[DDRB] &    8) ?"RRW:PB3:out ":"RRW:pb3:in  "),
                                ( (V->via[DDRB] &   16) ?"CMD:PB4:out ":"CMD:pb4:in  "),
                                ( (V->via[DDRB] &   32) ?"PAR:PB5:out ":"PAR:pb5:in  "),
                                ( (V->via[DDRB] &   64) ?"DSK:PB6:out ":"DSK:pb6:in  "),
                                ( (V->via[DDRB] &  128) ?"CRS:PB7:out ":"CRS:pb7:in  "));



            if ( xvalue  ) // only try the write if the mask has changed
                 viaX_orb(V,V->via[ORBB] & V->via[DDRB]); // output the data that was masked off
            return;

		case DDRA2  :         // and DDRA 3 registers

             DEBUG_LOG(0,"Overwriting DDRA (previous value was=%02x, new value is:%02x)",
                          V->via[DDRA],xvalue);

             V->via[DDRA]=xvalue;

             DEBUG_LOG(0,"Wrote DDRA mask=%02x:(%s%s%s%s%s%s%s%s)",V->via[DDRA],
                                ( (V->via[DDRA] &    1) ?"PA0:out ":"pb0:in  "),
                                ( (V->via[DDRA] &    2) ?"PA1:out ":"pb1:in  "),
                                ( (V->via[DDRA] &    4) ?"PA2:out ":"pb2:in  "),
                                ( (V->via[DDRA] &    8) ?"PA3:out ":"pb3:in  "),
                                ( (V->via[DDRA] &   16) ?"PA4:out ":"pb4:in  "),
                                ( (V->via[DDRA] &   32) ?"PA5:out ":"pb5:in  "),
                                ( (V->via[DDRA] &   64) ?"PA6:out ":"pb6:in  "),
                                ( (V->via[DDRA] &  128) ?"PA7:out ":"pb7:in  "));




            if (V->orapending && xvalue!=0) // only try to write if this mask changed and last access to A was a write
                {
                  DEBUG_LOG(0,"V->orapending=%02x, DDRA=%02x, last write was:%02x",
                            V->orapending,
                            xvalue,
                            V->via[ORAA] );

                  viaX_ora(V,(V->via[ORAA] & xvalue), ORA); //output the masked data
                }
			return;

		case T1LL2  :   // Timer 1 Low Order Latch
            DEBUG_LOG(0,"T1LL2");

            V->via[T1CL]=xvalue;                                               // 4 T1LC actually writes to T1LL only
            V->via[T1LL]=xvalue;
            V->t1_e=get_via_te_from_timer((V->via[T1LH]<<8)|V->via[T1LL]);

            FIX_CLKSTOP_VIA_T1(V->vianum);      // update cpu68k_clocks_stop if needed

            //#ifdef DEBUG
            V->t1_set_cpuclk=cpu68k_clocks;
            //#endif
            via_running=1;
            DEBUG_LOG(0,"ll-t1clk:%d T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((V->via[T1LH]<<8)|V->via[T1LL]) , V->t1_e, V->t1_e-cpu68k_clocks,cpu68k_clocks);

            return;                        // Set timer2 low byte

		case T1LH2  :
            DEBUG_LOG(0,"T1LH2");
            V->via[T1LH]=(xvalue);                                             // Set timer1 latch and counter
            via_running=1;
            //2005.05.31 - this next line was disabled - should it have been?
            //via[1].t1_e=get_via_te_from_timer((via[1].via[T1LH]<<8)|via[1].via[T1LL]);
            // VIA_CLEAR_IRQ_T1(1);     // clear T1 irq on T1 read low or write high - does this clear the timer?

            DEBUG_LOG(0,"lh-t1clk:%d (%04x) t1lh1=%02x T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((V->via[T1LH]<<8)|V->via[T1LL]) ,
                    ((V->via[T1LH]<<8)|V->via[T1LL]) , xvalue,
                    V->t1_e,
                    V->t1_e-cpu68k_clocks,cpu68k_clocks);

            return;

		case T1CL2  :
            DEBUG_LOG(0,"T1CL2");

            V->via[T1LL]=xvalue;

            //V->t1_e=get_via_te_from_timer((V->via[T1LH]<<8)|via[1].via[T1LL]);   // so, does this still count down? likely not!
            //FIX_CLKSTOP_VIA_T1(1);      // update cpu68k_clocks_stop if needed           // disable this code here.
            // V->t1_set_cpuclk=cpu68k_clocks;

            via_running=1;

            DEBUG_LOG(0,"cl-t1clk:%d (%04x) CL1=%02x T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((V->via[T1LH]<<8)|V->via[T1LL]) ,
                    ((V->via[T1LH]<<8)|V->via[T1LL]) , xvalue,
                    V->t1_e, V->t1_e-cpu68k_clocks,cpu68k_clocks);
            return;


        case T1CH2  :
            DEBUG_LOG(0,"T1CH");
            if ( V->via[ACR]&128) V->via[IRB] &= 0x7f;                             // with ACR7=1, a write to T1C brings PB7 low
            V->via[T1LH]=xvalue;                                                       // load into register
            V->via[T1CH]=V->via[T1LH]; V->via[T1CL]=V->via[T1LL];          // 5 T1HC actually writes to T1HL + copies T1LL->T1CL, T1LH->T1CH

            V->t1_e=get_via_te_from_timer((V->via[T1CH]<<8)|V->via[T1LL]);     // this one does tell the counter to count down!
            FIX_CLKSTOP_VIA_T1(2);                                                         // update cpu68k_clocks_stop if needed
            V->t1_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)

            VIA_CLEAR_IRQ_T1(V->vianum);     // clear T1 irq on T1 read low or write high

            DEBUG_LOG(0,"ch-t1clk:%d (%04x) CH1=%02x T1 will now expire at:%llx - %llx cycles from now - clock now:%llx",
                    ((V->via[T1LH]<<8)|V->via[T1LL]),
                    ((V->via[T1LH]<<8)|V->via[T1LL]), xvalue,
                    V->t1_e, V->t1_e-cpu68k_clocks,cpu68k_clocks);

            via_running=1;
            return;


        case T2CL2:  // Set Timer 2 Low Latch
            DEBUG_LOG(0,"T2CL");
            V->via[T2LL]=xvalue;                                                       // Set t2 latch low
            //V->via[T2CL]=xvalue;                                                       // NOT SURE ABout this one!  2004.12.02
            // no change to the counter! only the latch! //2005.06.05
            // V->t2_e=get_via_te_from_timer((V->via[T2LH]<<8)|V->via[T2CL]);     // set timer expiration
            //FIX_CLKSTOP_VIA_T2(1);                                                         // update cpu68k_clocks_stop if needed
            //V->t2_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)


            //#ifdef DEBUG
            V->t2_set_cpuclk=cpu68k_clocks;
            DEBUG_LOG(0,"t2clk:%d (write takes effect on write to T2H) T2 set to expire at clock:%llx time now is %llx which is %llx cycles from now",
                    ((V->via[T2LH]<<8)|V->via[T2CL]),V->t2_e,cpu68k_clocks,V->t2_e-cpu68k_clocks);
            //#endif
            via_running=1;
            return;

        case T2CH2: // timer2 high byte
              // a write to T2H will load and the counter as well.
            DEBUG_LOG(0,"T2CH");

            V->via[T2LH]=xvalue;                                                       // Set t2 latch high
            V->via[T2CH]=xvalue; V->via[T2CL]=V->via[T2LL];                    // load the counter with latches

            VIA_CLEAR_IRQ_T2(V->vianum);     // clear T2 irq on T2 read low or write high

            V->t2_e=get_via_te_from_timer((V->via[T2CH]<<8)|V->via[T2CL]);     // set timer expiration
            DEBUG_LOG(0,"V->t2_e=%ld",V->t2_e);
            FIX_CLKSTOP_VIA_T2(2);                                                         // update cpu68k_clocks_stop if needed
            V->t2_set_cpuclk=cpu68k_clocks;                                            // timer was set right now (at this clock)

            DEBUG_LOG(0,"t2clk:%d T2 set to expire at CPU clock:%llx time now is %llx which is %llx cycles from now.  stop is:%llx",
                    ((V->via[T2LH]<<8)|V->via[T2CL]),V->t2_e,cpu68k_clocks,V->t2_e-cpu68k_clocks,cpu68k_clocks_stop);

            via_running=1;

			return;


        case SR2:
            {
            //char srwrite[128];             //unused
            uint8 shift=(V->via[ACR] & 28)>>2;

            DEBUG_LOG(0,"Write %02x to shift register on VIA2!!!!",xvalue);
            //fprintf(buglog,"Write %02x to shift register on VIA2!!!!\n",xvalue);


           // #ifdef DEBUG
           // if (xvalue==0)  debug_off();
           // #endif


            // EXIT(53);

            DEBUG_LOG(0,"SR");
            V->via[SHIFTREG]=xvalue;                     // write shift register
            via_running=1;
            V->srcount=0;

            // if (shift==4) {} - free running mode from T2 - timing tied to T2
            // if (shift==5) {} - one shot T2 mode - timing tied to T2
            if (shift==6)    {V->sr_e=cpu68k_clocks+VIACLK_TO_CPUCLK(8); get_next_timer_event();}
            ///if (shift==6)    {V->sr_e=cpu68k_clocks+8*via_clock_diff; get_next_timer_event();}
            //if (shift==7) - not implemented since CB1 is not connected on Lisa I/O board

            VIA_CLEAR_IRQ_SR(V->vianum);     // clear SR irq on SR access
            }
            return;

        case ACR2 :
                    DEBUG_LOG(0,"ACR2 Port A Latching:%s  Port B Latching:%s",
                    ((xvalue & BIT0) ?"Enabled":"Disabled"),
                    ((xvalue & BIT1) ?"Enabled":"Disabled")  );
                    #ifdef DEBUG
                    switch(xvalue & (BIT4|BIT3|BIT2)>>2)  {
                      case 0:        DEBUG_LOG(0,"ACR2 SHIFT REG DISABLED");                    break;
                      case 1:        DEBUG_LOG(0,"ACR2 SR SHIFT IN UNDER COMTROL OF T2");       break;
                      case 2:        DEBUG_LOG(0,"ACR2 SR SHIFT IN UNDER CONTROL OF 02");       break;
                      case 3:        DEBUG_LOG(0,"ACR2 SR SHIFT IN UNDER CONTROL OF EXT.CLK");  break;
                      case 4:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT FREE-RUNNING AT T2 RATE");  break;
                      case 5:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT UNDER CONTROL OF T2");      break;
                      case 6:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT UNDER CONTROL OF 02");      break;
                      case 7:        DEBUG_LOG(0,"ACR2 SR SHIFT OUT UNDER CONTROL OF EXT.CLK"); break;
                    }

                    DEBUG_LOG(0,"ACR Timer2 Control: %s", ((xvalue & BIT6) ? "Countdown with PB6 Pulses":"Timed IRQ"));

                    switch(xvalue & (BIT7|BIT6)>>6)  {
                      case 0:        DEBUG_LOG(0,"ACR2 Timer1 Control: TIMED IRQ Each Time T1 Loaded, PB7 Output Disabled"); break;
                      case 1:        DEBUG_LOG(0,"ACR2 Timer1 Control: CONTINUOUS IRQ's, PB7 Output Disabled"); break;
                      case 2:        DEBUG_LOG(0,"ACR2 Timer1 Control: TIMED IRQ Each Time T1 is loaded, PB7 - One Shot Output"); break;
                      case 3:        DEBUG_LOG(0,"ACR2 Timer1 Control: Continous IRQ's, PB7: SQUARE WAVE OUTPUT"); break;
                    }
                    #endif
                    V->via[ACR]=xvalue; return;

        case PCR2 : DEBUG_LOG(0,"PCR via#%d",V->vianum);
                    #ifdef DEBUG
                    DEBUG_LOG(0,"PCR via#%d",V->vianum);
                    if (xvalue & 0)  {DEBUG_LOG(0,"PCR2: CA1 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE");}
                    else             {DEBUG_LOG(0,"PCR2: CA1 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE");}

                    switch((xvalue & 15)>>1) {
                      case 0 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE"); break;
                      case 1 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT Input NEG. Active Edge"); break;
                      case 2 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE"); break;
                      case 3 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT INPUT POSITIVE Active Edge"); break;
                      case 4 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: HANDSHAKE OUTPUT"); break;
                      case 5 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: PULSE OUTPUT"); break;
                      case 6 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: LOW OUTPUT"); break;
                      case 7 :        DEBUG_LOG(0,"PCR2: CA2 INTERRUPT CONTROL: HIGH OUTPUT"); break;
                    }
                    DEBUG_LOG(0,"PCR2: cb1 irq ctl:%s active edge",((xvalue & BIT4) ? "1:positive":"0:negative") );
                    switch((xvalue & (BIT7|BIT6|BIT5))>>5) {
                      case 0 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INPUT NEG. ACTIVE EDGE"); break;
                      case 1 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT Input NEG. Active Edge"); break;
                      case 2 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INPUT POS. ACTIVE EDGE"); break;
                      case 3 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: INDEPENDENT INTERRUPT INPUT POSITIVE Active Edge"); break;
                      case 4 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: HANDSHAKE OUTPUT"); break;
                      case 5 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: PULSE OUTPUT"); break;
                      case 6 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: LOW OUTPUT"); break;
                      case 7 :        DEBUG_LOG(0,"PCR2: CB2 INTERRUPT CONTROL: HIGH OUTPUT"); break;
                    }
                   #endif
             if ((V->via[PCR] ^ xvalue) & 1) V->via[IFR]|=2;
             V->via[PCR]=xvalue; return;

		case IFR2 :                      /* IFR  */

            V->via[IFR]&=(0x7f^(xvalue & 0x7f));  // 1 writes to IFR are used to clear bits!
            if ( V->via[IFR] & 127) V->via[IFR]|=128;   // if all are cleared, clear bit 7 else set it
            else V->via[IFR]=0;

            DEBUG_LOG(0,"IFR write bits: %s %s %s %s %s %s %s %s",
                           (V->via[IFR] &   1) ? "ifr0CA2:on"              :"ifr0CA2:off",
                           (V->via[IFR] &   2) ? "bsy_ifr1CA1:on"          :"bsy_ifr1CA1:off",
                           (V->via[IFR] &   4) ? "ifr2SR :on"              :"ifr2SR :off",
                           (V->via[IFR] &   8) ? "parity_ifr3CB2:on"       :"parity_ifr3CB2:off",
                           (V->via[IFR] &  16) ? "not_connected_ifr4CB1:on":"not_connected_ifr4CB1:off",
                           (V->via[IFR] &  32) ? "ifr5T2 :on"              :"ifr5T2 :off",
                           (V->via[IFR] &  64) ? "ifr6T1 :on"              :"ifr6T1 :off",
                           (V->via[IFR] & 128) ? "ifr7ANY:on"              :"ifr7ANY:off");
			return;


        case IER2 :
            DEBUG_LOG(0,"IER");
            //if bit 7=0, then all 1 bits are reversed. 1=no irq, 0=irq enabled.

            if  (xvalue & 0x80)  V->via[IER] |=       xvalue;
            else                 V->via[IER] &=(0x7f^(xvalue&0x7f));


            // from via 1// if bit 7=0, then all 1 bits are reversed. 1=no irq, 0=irq enabled.
            ///if   (xvalue & 128) {via[1].via[IER] |= xvalue;}
            ///else via[1].via[IER] &=(0x7f-( xvalue & 0x7f));
            #ifdef DEBUG
            if (xvalue & 0x80)
               {
                DEBUG_LOG(0,"VIA IER Write Set:%02x::%s %s %s %s %s %s %s %s\n",xvalue,
                ((xvalue & VIA_IRQ_BIT_CA2        ) ? "CA2":""),
                ((xvalue & VIA_IRQ_BIT_CA1        ) ? "CA1":""),
                ((xvalue & VIA_IRQ_BIT_SR         ) ? "SR ":""),
                ((xvalue & VIA_IRQ_BIT_CB2        ) ? "CB2":""),
                ((xvalue & VIA_IRQ_BIT_CB1        ) ? "CB1":""),
                ((xvalue & VIA_IRQ_BIT_T2         ) ? "T2 ":""),
                ((xvalue & VIA_IRQ_BIT_T1         ) ? "T1 ":""),
                ((xvalue & VIA_IRQ_BIT_SET_CLR_ANY) ? "SET":"CLEAR"));
               }
            else
               {
               DEBUG_LOG(0,"VIA IER clear Value:%02x::%s %s %s %s %s %s %s %s\n",V->via[IER],
                ((V->via[IER] & VIA_IRQ_BIT_CA2        ) ? "CA2":""),
                ((V->via[IER] & VIA_IRQ_BIT_CA1        ) ? "CA1":""),
                ((V->via[IER] & VIA_IRQ_BIT_SR         ) ? "SR ":""),
                ((V->via[IER] & VIA_IRQ_BIT_CB2        ) ? "CB2":""),
                ((V->via[IER] & VIA_IRQ_BIT_CB1        ) ? "CB1":""),
                ((V->via[IER] & VIA_IRQ_BIT_T2         ) ? "T2 ":""),
                ((V->via[IER] & VIA_IRQ_BIT_T1         ) ? "T1 ":""),
                ((V->via[IER] & VIA_IRQ_BIT_SET_CLR_ANY) ? "SET":"CLEAR"));
               }
            #endif
			return;
        default: DEBUG_LOG(0,"Illegal address error Write to illegal address in viaX_wb_ @ %08x",addr);
	}
	return;
}




void init_vias(void)
{
	int i,j;

    memset(&via[0],0,8*sizeof(ViaType));
    via[0].active=0;                    // sacrificial lamb. :)  (aka waste of memory)
	via[1].active=1;
	via[2].active=1;
	via[3].active=0;
	via[4].active=0;
	via[5].active=0;
	via[6].active=0;
	via[7].active=0;
    via[8].active=0;

	via[1].irqnum=2 ; //cops via
	via[2].irqnum=1 ; //parallel port via

	via[3].irqnum=5; //slot 1
	via[4].irqnum=5; //slot 1
	via[5].irqnum=4; //slot 2
	via[6].irqnum=4; //slot 2
	via[7].irqnum=3; //slot 3
	via[8].irqnum=3; //slot 3

	via[1].active=via[2].active=1;

	for (i=1; i<9; i++)
	{
		via[i].vianum=i;
		for (j=0; j<16; j++) via[i].via[j]=0;

        via[i].last_a_accs=0;
        via[i].irb=NULL;
		via[i].ira=NULL;
		via[i].orb=NULL;
		via[i].ora=NULL;
		via[i].ca1=0;
		via[i].ca2=0;
		via[i].cb1=0;
		via[i].cb2=0;
		via[i].srcount=0;
        via[i].ProFile=NULL;
        via[i].ADMP=0;
        via[i].t1_e=-1;
        via[i].t2_e=-1;
        via[i].t1_fired=0;
        via[i].t2_fired=0;
        //#ifdef DEBUG
        via[i].t1_set_cpuclk=0;
        via[i].t2_set_cpuclk=0;
        via[i].t1_fired_cpuclk=0;
        via[i].t2_fired_cpuclk=0;
        //#endif
	}


   via_running=0;


//#ifdef PROFILE_VIA2
//#else
//
//   via[2].ProFile=NULL;
//#endif
}

/* This is called by reg68k_external_execute in order to figure out whether or not
   one of the VIA timers will occur in the current video frame as called by emulate()
   in lisaem.c

   min_via_num is used as a return value to reg68k to signal which VIA timer is set.
   to find the via #, do (min_via_num & 0x7f)  To find out if it's timer 2 in that
   via do (min_via_num & 0x80)
*/




void reset_via(int i)
{

    via[1].irqnum=2; //cops via
    via[2].irqnum=1; //parallel port via

	via[3].irqnum=5; //slot 1
	via[4].irqnum=5; //slot 1

    via[5].irqnum=4; //slot 2
	via[6].irqnum=4; //slot 2

	via[7].irqnum=3; //slot 3
	via[8].irqnum=3; //slot 3


    via[1].vianum=1;
    via[2].vianum=2;
    via[3].vianum=3;
    via[4].vianum=4;
    via[5].vianum=5;
    via[6].vianum=6;
    via[7].vianum=7;
    via[8].vianum=8;


    via[1].active=1;
    via[2].active=1;
	via[i].srcount=0;
	via[i].vianum=i;
	via[i].via[0]=0;
	via[i].via[1]=0;
	via[i].via[2]=0;
	via[i].via[3]=0;

	via[i].via[11]=0;
	via[i].via[12]=0;
	via[i].via[13]=0;
	via[i].via[14]=0;
	via[i].via[15]=0;
	via[i].irb=NULL;
	via[i].ira=NULL;
	via[i].orb=NULL;
	via[i].ora=NULL;

	via[i].ca1=0;
	via[i].ca2=0;
	via[i].cb1=0;
	via[i].cb2=0;

    via_running=0;
}

/*
A1. Versatile Interface Adapter brief reference (from Synertek data sheet)
------------------------------------------------
Features:
        - two 8-bit bidirectional I/O ports
        - two 16-bit programmable Timer/counters
        - serial data port
        - CMOS compatible peripheral port A lines
        - expanded handshake capability allows positive control of data
        transfers between processor and peripheral devices
        - latched output and input registers
Peripheral A port (PA0-PA7):
        It consists of 8 lines which can be individually programmed to act
        as inputs or outputs under control of a Data Direction Register. The
        polarity of output pins is controlled by an Output Register and input
        data may be latched into an internal register under control of the CA1
        line.
Peripheral A Control Lines (CA1,CA2):
        The two peripheral A control lines act as interrupt inputs or as
        handshake outputs. Each line controls an internal interrupt flag with a
        corresponding interrupt enable bit. In addition, CA1 controls the
        latching of data on peripheral A port input lines (CA1 is an input only)
Peripheral B port (PB0-PB7):
        It consists of eight bi-directional lines which are controlled by an
        output register and a data direction register in much the same manner
        as the PA port. In addition, the PB7 output signal can be controlled
        by one of the interval timers while the second timer can be programmed
        to count pulses on the PB6 pin.
Peripheral B Control Lines (CB1,CB2):
        They act as interrupt inputs or as handshake outputs. As with CA1 and
        CA2, each line controls an interrupt flag with a corresponding interrupt
        enable bit. In addition, these lines act as a serial port under control
        of the Shift Register.
Registers
        Reading/writing registers of the chip allows to control the powerful
        features. A register is read or written when the chip is selected and
        the low four address bits indicate the desired register:
        Address Reg                     Description
                               (Write)       |      (Read)
        ----------------------------------------------------------------
        0000    ORB/IRB Output Register B    | Input Register B
        0001    ORA/IRA Output Register A    | Input Register A
        0010    DDRB            Data Direction Register B
        0011    DDRA            Data Direction Register A
        0100    T1C-L   T1 low-order Latches | T1 low-order Counter
        0101    T1C-H             T1 high-order Counter
        0110    T1L-L             T1 low-order Latches
        0111    T1L-H             T1 high-order Latches
        1000    T2C-L   T2 low-order Latches | T2 low-order Counter
        1001    T2C-H             T2 high-order Counter
        1010    SR                   Shift Register
        1011    ACR              Auxiliary Control Register
        1100    PCR             Peripheral Control Register
        1101    IFR               Interrupt Flag Register
        1110    IER             Interrupt Enable Register
        1111    ORA/IRA     Same as reg 1 except no handshake
Port A and Port B operation:
        Each 8-bit peripheral port has a Data Direction Register (DDRA, DDRB)
        for specifying whether the peripheral pins are to act as inputs or
        outputs. A 0 in a bit of the Data Direction Register causes the
        corresponding peripheral pin to act as an input. A 1 causes the pin to
        act as an output.
        When programmed as an output each peripheral pin is also controlled by
        a corresponding bit in the Output Register (ORA, ORB). A 1 in the
        Output Register causes the output to go high, and a 0 causes the output
        to go low. Data may be written into Output Register bits corresponding
        to pins which are programmed as inputs. In this case, however, the
        output signal is unaffected.
        Reading a peripheral port causes the contents of the Input Register
        (IRA, IRB) to be transferred onto the data bus. With input latching
        disabled, IRA will always reflect the levels on the PA pins. With
        input latching enabled and the selected active transition on CA1 having
        occurred, IRA will contain the data present on the PA lines at the time
        of the transition. Once IRA is read, however, it will appear transparent
        and will reflect the current state of the PA lines until the next
        latching transition.
        The IRB register operates similar to the IRA register. However, for pins
        programmed as outputs, there is a difference. When reading IRA, the
        level on the pin determines whether a 0 or a 1 is sensed. When reading
        IRB, however, the bit stored in the output register, ORB, is the bit
        sensed.
        Finally, the 6522 allows positive control of data transfers between the
        system processor and peripheral devices through the operation of
        handshakes lines. Port A lines (CA1, CA2) handshake data on both a read
        and a write operation while the Port B lines (CB1, CB2) handshake on a
        write operation only.
Read Handshake
        The peripheral device must generate the equivalent of a "data ready"
        signal to the processor signifying that valid data is present on the
        peripheral port. This signal normally interrupts the processor, which
        then reads the data, causing generation of a "data taken" signal.
        Automatic read handshaking is possible on the peripheral A port only.
        The CA1 interrupt input pin accepts the "data ready" signal and CA2
        generates the "data taken" signal. The "data ready" signal will set an
        internal flag which may interrupt the processor or which may be polled
        under program control. The "data taken" signal can either be a pulse
        or a level which is set low by the system processor and is cleared by
        the "data ready" signal.
Write Handshake
        For write handshaking, the 6522 generates the "data ready" signal and
        the peripheral device must respond with the "data taken" signal. This
        can be accomplished on both the PA port and the PB port. CA2 or CB2 act
        as a "data ready" output in either the handshake mode or pulse mode and
        CA1 or CB1 accept the "data taken" signal from the peripheral device,
        setting the interrupt flag and cleaning the "data ready" output.
        Selection of operating modes for CA1, CA2, CB1 and CB2 is accomplished
        by the Peripheral Control Register.
        Peripheral Control Register
                bit 0:          CA1 interrupt control
                        0 = negative active edge
                        1 = positive active edge
                bits 321:       CA2 control
                        000 = input, negative active edge
                        001 = independant interrupt input, negative edge
                        010 = input, positive active edge
                        011 = independent interrupt input, positive edge
                        100 = handshake output
                        101 = pulse output
                        110 = low output
                        111 = high output
                bit 4:          CB1 interrupt control
                        0 = negative active edge
                        1 = positive active edge
                bits 765:       CB2 control
                        000 = input, negative active edge
                        001 = independant interrupt input, negative edge
                        010 = input, positive active edge
                        011 = independent interrupt input, positive edge
                        100 = handshake output
                        101 = pulse output
                        110 = low output
                        111 = high output

Timer operation:
        Interval timer T1 consists of two 8-bit latches and a 16-bit counter.
        The latches are used to store data which is to be loaded into the
        counter. After loading, the counter decrements at 02 (Phi-2) clock rate.
        Upon reaching zero, an interrupt flag will be set, and an IRQ will be
        raised if the interrupt is enabled. The timer will then disable any
        further interrupts, or (when programmed to) will automatically transfer
        the contents of the latches into the counter and begin to decrement
        again. In addition, the timer may be programmed to invert the output
        signal on a peripheral pin each time it times-out.
        Two bits are provided in the Auxiliary Control Register (bits 6 and 7)
        to allow selection of the T1 operating modes.
        Auxiliary Control Register
                bit 0:          Port A Latch enable
                        0 = disable
                        1 = enable latching
                bit 1:          Port B Latch enable
                        0 = disable
                        1 = enable latching
                bits 432:       Shift Register Control
                        000 = disabled
                        001 = shift in under control of T2
                        010 = shift in under control of 02
                        011 = shift in under control of external clock
                        100 = shift out free-running at T2 rate
                        101 = shift out under control of T2
                        110 = shift out under control of 02
                        111 = shift out under control of external clock
                bit 5:          T2 timer control
                        0 = timed interrupt
                        1 = count down with pulses on PB6
                bits 76:        T1 timer control
                        00 = timed interrupt each time T1 is loaded,
                             PB7 disabled
                        01 = continuous interrupts,
                             PB7 disabled
                        10 = timed interrupt each time T1 is loaded,
                             one-shot output on PB7
                        11 = continuous interrupts,
                             square wave output on PB7
Timer 1 One-Shot Mode
        This allows generation of a single interrupt for each Timer load
        operation. In addition, Timer 1 can be programmed to produce a single
        negative pulse on PB7.
        To generate a single interrupt, ACR bits 6 and 7 must be 0 then either
        T1L-L or T1C-L must be written with the low-order count value. (A write
        to T1C-L is effectively a write to T1L-L). Next the higher-order count
        value is written to T1C-H, (the value is simultaneously written into
        T1L-H), and T1L-L is transferred to T1C-L. Countdown begins on the 02
        following the write T1C-H and decrements at the 02 rate. T1 interrupt
        occurs when the counters reach 0. Generation of a negative pulse on PB7
        is done in the same manner except ACR bit 7 must be a one. PB7 will go
        low after a write T1C-H and go high again when the counters reach 0.
        The T1 interrupt flag is reset by either writing T1C-H (starting a new
        count) or by reading T1C-L.

Timer 1 Free-Run Mode
        The most important advantage associated with the latches in T1 is the
        ability to produce a continuous series of evenly spaces interrupts and
        the ability to produce a square wave on PB7 whose frequency is not
        affected by variations in the processor interrupt response time.
        In the free-running mode, the interrupt flag is set and the signal on
        PB7 is inverted each time the counter reaches zero. However, instead
        of continuing to decrement from zero after a time-out, the timer
        automatically transfers the contents of the latch into the counter (16
        bits) and continues to decrement from there. It is not necessary to
        rewrite the timer to enable setting the interrupt flag on the next
        time-out. The interrupt flag can be cleared by reading T1C-L, by writing
        directly into the flag as described later, or if a new count value is
        desired by a write to T1C-H.

        All interval timers are re-triggerable. Rewriting the counter will
        always re-initialize the time-out period. In fact, the time-out can be
        prevented completely if the processor continues to rewrite the timer
        before it reaches zero. Timer 1 will operate in this manner if the
        processor writes into the high order counter (T1C-H). However, by
        loading the latches only, the processor can access the timer during
        each down-counting operation without affecting the time-out in process.
        Instead, the data loaded into the latches will determine the length of
        the next time-out period. This capability is particularly valuable in
        the free-running mode with the output enabled. In this mode, the signal
        on PB7 is inverted and the interrupt flag is set with each time-out. By
        responding to the interrupts with new data for the latches, the
        processor can determine the period of the next half cycle during each
        half cycle of the output signal on PB7. In this manner, very complex
        waveforms can be generated.
Timer 2 operation
        Timer 2 operates as an interval timer (in the one-shot mode only), or
        as a counter for counting negative pulses on the PB6 peripheral pin. A
        single control bit is provided in the Auxiliary Control Register to
        select between these two modes. This timer is comprised of a write-only
        low-order latch (T2L-L), a read-only low-order counter and a read/write
        high order counter. The counter registers act as a 16-bit counter which
        decrements at 02 rate.
Timer 2 One-shot Mode
        In this mode, T2 provides a single interrupt for each write T2C-H
        operation. After timing-out, (reading 0) the counters roll-over to all
        1's (FFFF) and continue decrementing, allowing the user to read them
        and determine how long T2 interrupt has been set. However, setting of
        the interrupt flag will be disabled after initial time-out so that it
        will not be set by the counter continuing to decrement through zero. The
        processor must rewrite T2C-H to enable setting of the interrupt flag.
        The interrupt flag is cleared by reading T2C-L or by writing T2C-H.
Timer 2 Pulse Counting Mode
        In the pulse counting mode, T2 serves primarily to count a predetermined
        number of negative-going pulses on PB6. This is accomplished by first
        loading a number into T2. Writing into T2C-H clears the interrupt flag
        and allows the counter to decrement each time a pulse is applied to PB6.
        The interrupt flag will be set when T2 reaches zero. At this time the
        counter will continue to decrement with each pulse on PB6. However, it
        is necessary to rewrite T2C-H to allow the interrupt flag to set on
        subsequent down-counting operations.
Shift Register operation
        The Shift Register (SR) performs serial data transfers into and out of
        the CB2 pin under control of an internal modulo-8 counter. Shift pulses
        can be applied to the CB1 pin from an external source or, with the
        proper mode selection, shift pulses generated internally will appear on
        the CB1 pin for controlling external devices.
        The control bits which select the various shift register operating modes
        are located in the Auxiliary Control Register (see above).
        Shift in under control of T2
                The shifting rate is controlled by the low-order 8 bits of T2.
                Shift pulses are generated on the CB1 pin to control shifting
                in external devices. The time between transitions of this output
                clock is a function of the system clock period and the contents
                of the low-order T2 latch.
                The shifting operation is triggered by writing or reading the
                shift register. Data is shifted first into the low order bit of
                SR and is then shifted into the next higher order bit of the
                shift register on the negative-going edge of each clock pulse.
                The input data should change before the positive-going edge of
                the CB1 clock pulse. This data is shifted into SR during the 02
                clock cycle following the positive-going edge of the CB1 clock
                pulse. After 8 CB1 clock pulses, the shift register interrupt
                flag will be set and IRQ will be raised.
        Shift in under control of 02
                CB1 becomes an output which generates shift pulses for
                controlling external devices. Timer 2 operates as an independent
                interval timer and has no effect on SR. The shifting operation
                is triggered by reading or writing the Shift Register. Data is
                shifted first into bit 0 and is then shifted into the next
                higher order bit of the shift register on the trailing edge of
                each 02 clock pulse. After 8 clock pulses, the shift register
                interrupt flag will be set, and the output clock pulses on CB1
                will stop.
        Shift in under control of external CB1 clock
                CB1 becomes an input. This allows an external device to load the
                shift register at its own pace. The shift register counter will
                interrupt the processor each time 8 bits have been shifted in.
                However, the shift register counter does not stop the shifting
                operation; it acts simply as a pulse counter. Reading or writing
                the Shift Register resets the Interrupt flag and initializes the
                SR counter to count another 8 pulses.
                Note that the data is shifted during the first system clock
                cycle following the positive-going edge of the CB1 shift pulse.
                For this reason, data must be held stable during the first full
                cycle following CB1 going high.
        Shift out free-running at T2 rate
                Very similar to next mode. However, the SR counter does not stop
                the shifting operation. Since the Shift Register bit 7 is
                recirculated back into bit 0, the 8 bits loaded into the shift
                register will be clocked onto CB2 repetitively. In this mode,
                the shift register counter is disabled, and IRQ is never set.
        Shift out under control of T2
                With each read or write of the shift register the SR counter is
                reset and 8 bits are shifted onto CB2. At the same time, 8 shift
                pulses are generated on CB1 to control shifting in external
                devices. After the 8 shift pulses, the shifting is disabled, the
                SR interrupt flag is set and CB2 remains at the last data level.
        Shift out under control of 02
                Same as previous mode but the shift rate is controlled by the
                02 system clock.
        Shift out under control of external CB1 clock
                Shifting is controlled by pulses applied to the CB1 pin by an
                external device. The SR counter sets the SR interrupt flag each
                time it counts 8 pulses but it does not disable the shifting
                function. Each time the microprocessor writes or read the shift
                register, the SR Interrupt flag is reset and the SR counter is
                initialized to begin counting the next 8 shift pulses on pin
                CB1. After 8 shift pulses, the interrupt flag is set. The
                microprocessor can then load the shift register with the next
                byte of data.
Interrupt operation
        Controlling interrupts within the 6522 involves three principal
        operations. These are flagging the interrupts, enabling interrupts and
        signaling to the processor that an active interrupt exists within the
        chip. Interrupt flags are set by interrupt conditions which exists
        within the chip or on inputs to the chip. These flags normally remain
        set until the interrupt has been serviced. To determine the source of
        an interrupt, the microprocessor must examine these flags in order
        from highest to lowest priority. This is accomplished by reading the
        flag register into the processor accumulator, shifting this register
        either right or left and then using conditional branch instructions to
        detect an active interrupt.
        Associated with each interrupt flag is an interrupt enable bit. This
        can be set or cleared by the processor to enable interrupting the
        processor from the corresponding interrupt flag. If an interrupt flag
        is set to a logic 1 by an interrupting condition, and the corresponding
        interrupt enable bit is set to a 1, the Interrupt Request output will
        go low (negative logic).
        All the interrupt flags are contained in one register. In addition, bit
        7 of this register will be read as a logic 1 when an interrupt exists
        within the chip. This allows very convenient polling of several devices
        within a system to locate the source of an interrupt.
        The Interrupt Flag Register (IFR) may be read directly by the processor.
        In addition, individual flag bits may be cleared by writing a 1 into the
        appropriate bit of the IFR. When the proper chip select and register
        signals are applied to the chip, the contents of this register are
        placed on the data bus. Bit 7 indicates the status of the IRQ output.
        This bit corresponds to the logic function
        IFR6*IER6+IFR5*IER5+IFR4*IER4+IFR3*IER3+IFR2*IER2+IFR1*IER1+IFR0*IER0
        (note: * = logic AND, + = logic OR)
        The IFR bit 7 is not a flag. Therefore, this bit is not directly cleared
        by writing a logic 1 into it. It can only be cleared by clearing all the
        flags in the register or by disabling all the active interrupts as
        discussed in next section.
        For each interrupt flag in IFR, there is a corresponding bit in the
        Interrupt Enable Register (IER). The system processor can set or clear
        selected bits in this register to facilitate controlling individual
        interrupts without affecting others. This is accomplished by writing to
        IER. If bit 7 of the data placed on the system data busduring this
        write operation is a 0, each 1 in bits 6 through 0 clears the
        corresponding bit in the IER. For each zero in bits 6 through 0, the
        corresponding bit is unaffected.
        Setting selected bits in the IER is accomplished by writing to it with
        bit 7 in the data word set to a logic 1. In this case, each 1 in bits 6
        through 0 will set the corresponding bit. For each zero, the
        corresponding bit will be unaffected. This individual control of the
        setting and clearing operations allows very convenient control of the
        interrupts during system operation.
        In addition to setting and clearing IER bits, the processor can read the
        contents of this register, bit 7 will be read as a logic 1.
        Interrupt Flag Register
                bit  |    set by                 | cleared by
                -------------------------------------------------------------
                0      CA2 active edge             read or write reg 1 (ORA) *
                1      CA1 active edge             read or write reg 1 (ORA)
                2      complete 8 shifts           read or write shift reg
                3      CB2 active edge             read or write ORB *
                4      CB1 active edge             read or write ORB
                5      time-out of T2              read T2 low or write T2 high
                6      time-out of T1              read T1 low or write T1 high
                7      any enabled interrupt       clear all interrupts
        note * : if the CA2/CB2 control in the PCR is selected as independent
        interrupt input, then reading or writing the output register ORA/ORB
        will NOT clear the flag bit. Instead, the bit must be cleared by writing
        into the IFR, as described previously.
 */


//sitting in the lab, and I'm codin' all night
//project won't compile, it'll be alright
//computer science for life, and that's my direction
//instead of b-balls, my homies throw exceptions    --mc++
