/*****************************************************************************/
/*                                                                           */
/*   VECTREX HP3000 Software Emulator              Copyright K.Wilkins 1996  */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Title      : 6522A PIA Software emulation module                        */
/*                                                                           */
/*   File Name  : EMU6522.C                                                  */
/*                                                                           */
/*   Author     : Keith Wilkins / C.S.                                       */
/*                                                                           */
/*   Version    : 1.20                                                       */
/*                                                                           */
/*   Desciption : This file contains the functions that emulate the 6522 PIA */
/*                Chip. Any emulation functions calling the read write       */
/*                functions will cause an immediate update to the PIA and    */
/*                and all associated variables. Changes occur instantly so   */
/*                there is no direct time based simulation.                  */
/*                                                                           */
/*   Functions  : f6522AInit()           - Init the 6522 PIA                 */
/*                f6522AReset()          - Reset the PIA                     */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Revision History:                                                       */
/*                                                                           */
/*   Version    Date    Who  Description of changes                          */
/*   -------    ----    ---  ----------------------                          */
/*                                                                           */
/*    0.01    14/03/93  K.W  Creation of empty file and descriptions         */
/*    1.00    05/08/96  K.W  Public release of DVE V1.0                      */
/*    1.20    20/10/96  C.S  Small changes here and there                    */
/*                                                                           */
/*****************************************************************************/
#ifdef _NO_DEBUG_INFORMATION_

#include <stdlib.h>

#include <standard.h>
#include <tools.h>

#include "emu6809.h"
#include "analog.h"
#include "sound.h"
#include "vdebug.h"
#include "verror.h"
#include "vectrex.h"
#include "sequence.h" //
#include "emu6522.h"
/*********************************/
/* 6522 Internal state variables */
/*********************************/
#ifdef PATCH_OFFSET
T_INT wait_ramp=T_WAIT_NOT;
//T_ULONG patch_start=0;
#endif

#ifdef ANALOG_CYCLE_PATCH

T_UWORD SAMPLE_HOLD_REACT_OFFSET_CYCLES=1;
T_UWORD DAC_REACT_OFFSET_CYCLES=1;
T_UWORD BLANK_REACT_OFFSET_CYCLES=1;
T_UWORD RAMP_REACT_OFFSET_CYCLES=1;
T_UWORD ZERO_REACT_OFFSET_CYCLES=1;

T_UWORD patch_must_be_applied=0;

T_UWORD ramp_patch=0;
T_UWORD ramp_patch_queue_depth=0;
T_UWORD ramp_patch_cycle_countdown[MAX_RAMP_QUEUE_DEPTH];
T_UWORD ramp_set_to[MAX_RAMP_QUEUE_DEPTH];
T_UCHAR tSIGDEF_RAMPB=0;

T_UWORD blank_patch=0;
T_UWORD blank_patch_queue_depth=0;
T_UWORD blank_patch_cycle_countdown[MAX_BLANK_QUEUE_DEPTH];
T_UWORD blank_set_to[MAX_BLANK_QUEUE_DEPTH];
T_UCHAR tSIGDEF_BLANKB=0;

T_UWORD zero_patch=0;
T_UWORD zero_patch_queue_depth=0;
T_UWORD zero_patch_cycle_countdown[MAX_ZERO_QUEUE_DEPTH];
T_UWORD zero_set_to[MAX_ZERO_QUEUE_DEPTH];
T_UCHAR tSIGDEF_ZEROB=0;

T_UWORD dac_patch=0;
T_UWORD dac_patch_queue_depth=0;
T_UWORD dac_patch_cycle_countdown[MAX_DAC_QUEUE_DEPTH];
T_SCHAR dac_set_to[MAX_DAC_QUEUE_DEPTH];
T_SCHAR tSIGDEF_DACBUS;

T_UWORD sample_hold_patch=0;
T_UWORD sample_hold_patch_queue_depth=0;
T_UWORD sample_hold_patch_cycle_countdown[MAX_SAMPLE_HOLD_QUEUE_DEPTH];
T_UWORD sample_hold_set_to[MAX_SAMPLE_HOLD_QUEUE_DEPTH];
T_UWORD mux_select_set_to[MAX_SAMPLE_HOLD_QUEUE_DEPTH];
T_UCHAR tSIGDEF_SAMPHOLD;
T_UCHAR tSIGDEF_AMUXSEL;




#endif

T_UCHAR      t6522ORB_0=0;           // Output register B - Bit 0 - Sample/Hold
T_UCHAR      t6522IRB_0=0;           // Input  register B - Bit 0 - Sample/Hold
T_UCHAR      t6522IRB_0L=0;          // Input  register B - Bit 0 - Sample/Hold (Latched)

T_UCHAR      t6522ORB_1=0;           // Output register B - Bit 1/2 - Analog mux select bit 0
T_UCHAR      t6522IRB_1=0;           // Input  register B - Bit 1/2 - Analog mux select
T_UCHAR      t6522IRB_1L=0;          // Input  register B - Bit 1/2 - Analog mux (Latched)

T_UCHAR      t6522ORB_2=0;           // Output register B - Bit 1/2 - Analog mux select bit 1
T_UCHAR      t6522IRB_2=0;           // Input  register B - Bit 1/2 - Analog mux select
T_UCHAR      t6522IRB_2L=0;          // Input  register B - Bit 1/2 - Analog mux (Latched)

T_UCHAR      t6522ORB_3=0;           // Output register B - Bit 3 - Sound Chip BC1
T_UCHAR      t6522IRB_3=0;           // Input  register B - Bit 3 - Sound Chip BC1
T_UCHAR      t6522IRB_3L=0;          // Input  register B - Bit 3 - Sound Chip BC1 (Latched)

T_UCHAR      t6522ORB_4=0;           // Output register B - Bit 4 - Sound Chip BDIR
T_UCHAR      t6522IRB_4=0;           // Input  register B - Bit 4 - Sound Chip BDIR
T_UCHAR      t6522IRB_4L=0;          // Input  register B - Bit 4 - Sound Chip BDIR (Latched)

T_UCHAR      t6522ORB_5=0;           // Output register B - Bit 5 - Compare
T_UCHAR      t6522IRB_5=0;           // Input  register B - Bit 5 - Compare
T_UCHAR      t6522IRB_5L=0;          // Input  register B - Bit 5 - Compare (Latched)

T_UCHAR      t6522ORB_6=0;           // Output register B - Bit 6 - Cartridge
T_UCHAR      t6522IRB_6=0;           // Input  register B - Bit 6 - Cartridge
T_UCHAR      t6522IRB_6L=0;          // Input  register B - Bit 6 - Cartridge (Latched)

T_UCHAR      t6522ORB_7REG=0;        // Output register B - Bit 7 - Ramp (register only copy)
T_UCHAR      t6522ORB_7=0;           // Output register B - Bit 7 - Ramp (Actual output bit)
T_UCHAR      t6522IRB_7=0;           // Input  register B - Bit 7 - Ramp
T_UCHAR      t6522IRB_7L=0;          // Input  register B - Bit 7 - Ramp (Latched)

T_UCHAR      t6522ORA=0;             // Output register A
T_UCHAR      t6522IRA=0;             // Input register A
T_UCHAR      t6522IRAL=0;            // Input register A latch

T_UCHAR      t6522DDRB=0;            // Data Direction reg B     0x00
T_UCHAR      t6522DDRA=0;            // Data Direction reg A     0x01

T_UCHAR      t6522SHFTREG=0;         // Shift Register           0x0a
T_UCHAR      t6522SHFTREGACT=0;

TIMER      u6522Timer1;            // Timer structures
TIMER      u6522Timer2;
T_INT      bTimer2OneShot=T_FALSE;

T_UCHAR      t6522AUX_T1CTRL=0;      // Aux register T1 Control
T_UCHAR      t6522AUX_T2CTRL=0;      // Aux register T2 Control
T_UCHAR      t6522AUX_SHFTCTRL=0;    // Aux register shift register control
T_UCHAR      t6522AUX_PA_LE=0;       // Aux register port A latch enable
T_UCHAR      t6522AUX_PB_LE=0;       // Aux register port B latch enable

T_UCHAR      t6522PCR_CB2CTRL=0;     // Peripheral ctrl reg CB2
T_UCHAR      t6522PCR_CB1CTRL=0;     // Peripheral ctrl reg CB1
T_UCHAR      t6522PCR_CA2CTRL=0;     // Peripheral ctrl reg CA2
T_UCHAR      t6522PCR_CA1CTRL=0;     // Peripheral ctrl reg CA1

T_UCHAR      t6522IER=0;

T_UCHAR      t6522IFLG=0;

T_UCHAR      t6522CA1=0;             // CA1 Pin
T_UCHAR      t6522CA2=0;             // CA2 Pin
T_UCHAR      t6522CB1=0;             // CB1 Pin
T_UCHAR      t6522CB2=0;             // CB2 Pin

/**************************/
/* some new global data's */
/**************************/
T_SWORD iToggle=0;
T_LONG tcount=0;
T_UCHAR (* f6522Addr0DRead)(T_UWORD tAddress);

/***********************************************************************/
/* Dirty little helper, small but effectiv (mainly for spike, it's the */
/* only program I know which uses T1 Interrupt on PIA)                 */
/***********************************************************************/
T_INT t1int=T_FALSE;
static T_UCHAR tFirstTime=T_TRUE;

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Init()                                               */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Initialise the 6522A emulation and register it with the   */
/*                 CPU as a memory mapped device.                            */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : BYTE T_TRUE/T_FALSE depending on init success/fail            */
/*                                                                           */
/*****************************************************************************/

T_INT f6522Init(T_VOID)
{
 T_UWORD loop;

 if(tFirstTime==T_TRUE)
 {
  tFirstTime=T_FALSE;
  for(loop=0;loop<128;loop++)
  {
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR00,1,f6522Addr00Read,f6522Addr00Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR01,1,f6522Addr01Read,f6522Addr01Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR02,1,f6522Addr02Read,f6522Addr02Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR03,1,f6522Addr03Read,f6522Addr03Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR04,1,f6522Addr04Read,f6522Addr04Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR05,1,f6522Addr05Read,f6522Addr05Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR06,1,f6522Addr06Read,f6522Addr06Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR07,1,f6522Addr07Read,f6522Addr07Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR08,1,f6522Addr08Read,f6522Addr08Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR09,1,f6522Addr09Read,f6522Addr09Write)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR0A,1,f6522Addr0ARead,f6522Addr0AWrite)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR0B,1,f6522Addr0BRead,f6522Addr0BWrite)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR0C,1,f6522Addr0CRead,f6522Addr0CWrite)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR0D,1,f6522Addr0DRead,f6522Addr0DWrite)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR0E,1,f6522Addr0ERead,f6522Addr0EWrite)==T_FALSE) return(T_FALSE);
   if(f6809DeclareAddress((loop*16)+PIA6522_ADDR0F,1,f6522Addr0FRead,f6522Addr0FWrite)==T_FALSE) return(T_FALSE);
  }
 }
 f6522Reset();
 return(T_TRUE);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Reset()                                              */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Perform a hardware reset of the 6522A PIA                 */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_VOID f6522Reset(T_VOID)
{
#ifdef ANALOG_CYCLE_PATCH
 tSIGDEF_RAMPB=0;
 tSIGDEF_BLANKB=0;
 tSIGDEF_DACBUS=0;
 tSIGDEF_SAMPHOLD=0;
 tSIGDEF_AMUXSEL=0;
 tSIGDEF_ZEROB=0;
#endif
 t6522ORB_0=0;
 t6522IRB_0=0;
 t6522IRB_0L=0;

 t6522ORB_1=0;
 t6522IRB_1=0;
 t6522IRB_1L=0;

 t6522ORB_2=0;
 t6522IRB_2=0;
 t6522IRB_2L=0;

 t6522ORB_3=0;
 t6522IRB_3=0;
 t6522IRB_3L=0;

 t6522ORB_4=0;
 t6522IRB_4=0;
 t6522IRB_4L=0;

 t6522ORB_5=0;
 t6522IRB_5=0;
 t6522IRB_5L=0;

 t6522ORB_6=0;
 t6522IRB_6=0;
 t6522IRB_6L=0;

 t6522ORB_7=0;
 t6522IRB_7=0;
 t6522IRB_7L=0;

 t6522ORA=0;
 t6522IRA=0;
 t6522IRAL=0;
 t6522DDRB=0;
 t6522DDRA=0;
 t6522SHFTREG=0;
 t6522SHFTREGACT=0;

 u6522Timer1.uLatch.tW=0xffff;
 u6522Timer1.uCount.tW=0;
 u6522Timer2.uLatch.tW=0xffff;
 u6522Timer2.uCount.tW=0;
 bTimer2OneShot=T_FALSE;

 t6522AUX_T1CTRL=0;
 t6522AUX_T2CTRL=0;
 t6522AUX_SHFTCTRL=0;
 t6522AUX_PA_LE=0;
 t6522AUX_PB_LE=0;

 t6522PCR_CB2CTRL=0;
 t6522PCR_CB1CTRL=0;
 t6522PCR_CA2CTRL=0;
 t6522PCR_CA1CTRL=0;

 t6522IER=0;

 t6522IFLG=0;

 t6522CA1=0;
 t6522CA2=0;
 t6522CB1=0;
 t6522CB2=0;
}
#endif //#ifdef _NO_DEBUG_INFORMATION_

#ifndef _NO_DEBUG_INFORMATION_

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Tick()                                               */
/*                                                                           */
/*   Author      : K.W / C.S.                                                */
/*                                                                           */
/*   Description : Perform a single tick of the 6522 counters                */
/*                 Sometimes inline...                                       */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_VOID f6522Tick(T_VOID)
{
#define PIA_TIMER1
#define PIA_TIMER2
#define PIA_SHIFT
#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef PIA_TIMER1
#undef PIA_TIMER2
#undef PIA_SHIFT
#undef SEQUENCER_ANALOG_CYCLE_PATCH
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr00Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 'B' input/ouput register               */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr00Read(T_UWORD tAddress)
{
 T_UCHAR   tData;
 // Before we do the read update the compare register

 fAnalogJoystickUpdate();

 // Build the read byte

 tData=0;
 tData|=t6522ORB_0 & t6522DDRB;         // Add output bits
 tData|=t6522ORB_1 & t6522DDRB;         // Add output bits
 tData|=t6522ORB_2 & t6522DDRB;         // Add output bits
 tData|=t6522ORB_3 & t6522DDRB;         // Add output bits
 tData|=t6522ORB_4 & t6522DDRB;         // Add output bits
 tData|=t6522ORB_5 & t6522DDRB;         // Add output bits
 tData|=t6522ORB_6 & t6522DDRB;         // Add output bits
 tData|=t6522ORB_7 & t6522DDRB;         // Add output bits

 // Check if latched version should be used

 if (t6522AUX_PB_LE)
 {
  fopen_monitor_debug_pause();
#define _fDebug(level,body) ((bGblDebugEnable==T_TRUE && level>=tGblDebugLevel)?(tGblDebugMsgLevel=level),(fDebugXX body):0)
  _fDebug(HIGH,("f6522Addr00Read()  - f6522Addr00Read latch read not supported (DATA:%02x)",tData));
#undef _fDebug
  tData|=t6522IRB_0L & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_1L & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_2L & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_3L & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_4L & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_5L & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_6L & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_7L & (t6522DDRB^0xff);  // Add input bits
 }
 else
 {
  tData|=t6522IRB_0 & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_1 & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_2 & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_3 & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_4 & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_5 & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_6 & (t6522DDRB^0xff);  // Add input bits
  tData|=t6522IRB_7 & (t6522DDRB^0xff);  // Add input bits
 }
 fDebug(MID,("f6522Addr00Read()  - Input/Output register B read (%02x)",tData));

 // Clear interrupt flag

 if (t6522PCR_CB2CTRL!=1 && t6522PCR_CB2CTRL!=3)
  t6522IFLG&=(E6522IFLG_CB2^0xff);
 t6522IFLG&=(E6522IFLG_CB1^0xff);
 return(tData);
}

T_UCHAR f6522Addr00Write(T_UWORD tAddress,T_UCHAR tData)
{
 t6522ORB_0=TMPL_RB_0 & tData;      // Add output bits
 t6522ORB_1=TMPL_RB_1 & tData;      // Add output bits
 t6522ORB_2=TMPL_RB_2 & tData;      // Add output bits
 t6522ORB_3=TMPL_RB_3 & tData;      // Add output bits
 t6522ORB_4=TMPL_RB_4 & tData;      // Add output bits
 t6522ORB_5=TMPL_RB_5 & tData;      // Add output bits
 t6522ORB_6=TMPL_RB_6 & tData;      // Add output bits

//t_printf(E_VERBOSE_NONE,"\n0=%i,1=%i,2=%i",t6522ORB_0,t6522ORB_1,t6522ORB_2);
//-Special case of PB7 & Timer 1 overide

 t6522ORB_7REG=TMPL_RB_7 & tData;      // Always copy reg value
// Only send to PB7 if allowed

 if ((t6522AUX_T1CTRL&0x02)==0)
 {
  t6522ORB_7=t6522ORB_7REG;
#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=RAMP_TEST_BIT;
   ramp_patch_cycle_countdown[ramp_patch_queue_depth]=RAMP_REACT_OFFSET_CYCLES;
   ramp_set_to[ramp_patch_queue_depth]=t6522ORB_7;
   ramp_patch_queue_depth++;
#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef SEQUENCER_ANALOG_CYCLE_PATCH


#endif
 }
#ifdef PATCH_OFFSET
// patch_start=lwGblSystemTickTotal;
// if ((wait_ramp==1)&&(!t6522ORB_7REG)) wait_ramp=T_FALSE;
 if (!t6522ORB_7)
 {
  if (wait_ramp==T_WAIT_SHIFTING)
   wait_ramp=T_WAIT_RAMP_ACCESS;
  else
   wait_ramp=T_WAIT_NOT;
 }
#endif

 fDebug(MID,("f6522Addr00Write() - Input/Output register B write (%02x)",tData));

 // Clear interrupt flag
 if (t6522PCR_CB2CTRL!=1 && t6522PCR_CB2CTRL!=3)
  t6522IFLG&=(E6522IFLG_CB2^0xff);
 t6522IFLG&=(E6522IFLG_CB1^0xff);

 // Update analog hardware & sound chip
 if (t6522ORB_0+t6522ORB_1+t6522ORB_2==2+4)
 {
  //printf("toll");
  digisound=T_TRUE;
 }
 else
  digisound=T_FALSE;

#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=SAMPLE_HOLD_TEST_BIT;
   sample_hold_patch_cycle_countdown[sample_hold_patch_queue_depth]=SAMPLE_HOLD_REACT_OFFSET_CYCLES;
   sample_hold_set_to[sample_hold_patch_queue_depth]=t6522ORB_0;
   mux_select_set_to[sample_hold_patch_queue_depth]=(t6522ORB_1 |t6522ORB_2);
   sample_hold_patch_queue_depth++;

#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef SEQUENCER_ANALOG_CYCLE_PATCH

#endif

 fAnalogTick();
 fSoundTick();
 return(tData);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr01Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 'A' input/ouput register               */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr01Read(T_UWORD tAddress)
{
   T_UCHAR   tData;
   tData=t6522ORA&t6522DDRA;           // Add output bits
   // Check if latched input should be used

   if(t6522AUX_PA_LE)
   {
    tData|=t6522IRAL&(t6522DDRA^0xff);   // Add input bits
   }
   else
   {
    tData|=t6522IRA&(t6522DDRA^0xff);   // Add input bits
   }
   fDebug(MID,("f6522Addr01Read()  - Input/Output register A read (%02x)",tData));
//   *** ADD HANDSHAKING ***
   // Clear interrupt flag
   if (t6522PCR_CA2CTRL!=1 && t6522PCR_CA2CTRL!=3)
    t6522IFLG&=(E6522IFLG_CA2^0xff);
   t6522IFLG&=(E6522IFLG_CA1^0xff);

   return(tData);
}


T_UCHAR f6522Addr01Write(T_UWORD tAddress,T_UCHAR tData)
{
   t6522ORA=tData;

   fDebug(MID,("f6522Addr01Write() - Input/Output register A write (%02x)",tData));
   // Clear interrupt flag
   if(t6522PCR_CA2CTRL!=1 && t6522PCR_CA2CTRL!=3)
    t6522IFLG&=(E6522IFLG_CA2^0xff);
   t6522IFLG&=(E6522IFLG_CA1^0xff);
   // Update analog hardware & sound chip
#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=DAC_TEST_BIT;
   dac_patch_cycle_countdown[dac_patch_queue_depth]=DAC_REACT_OFFSET_CYCLES;
   dac_set_to[dac_patch_queue_depth]=t6522ORA;
   dac_patch_queue_depth++;

#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef SEQUENCER_ANALOG_CYCLE_PATCH
#else
   fAnalogTick();
   fSoundTick();
#endif
   return(tData);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr02Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 'B' data direction register            */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr02Read(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr02Read()  - Data Direction B read (%02x)",t6522DDRB));
   return(t6522DDRB);
}


T_UCHAR f6522Addr02Write(T_UWORD tAddress,T_UCHAR tData)
{
 t6522DDRB=tData;
 fDebug(MID,("f6522Addr02Write() - Data Direction B write (%02x)",t6522DDRB));
 return(t6522DDRB);
}



/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr03Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 'A' data direction register            */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr03Read(T_UWORD tAddress)
{
// tAddress=0; // Stop compiler warning
   fDebug(MID,("f6522Addr03Read()  - Data Direction A read (%02x)",t6522DDRA));
   return(t6522DDRA);
}


T_UCHAR f6522Addr03Write(T_UWORD tAddress,T_UCHAR tData)
{
// tAddress=0; // Stop compiler warning
   t6522DDRA=tData;
   fDebug(MID,("f6522Addr03Write() - Data Direction A write (%02x)",t6522DDRA));
   return(t6522DDRA);
}




/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr04Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 T1 low order latches/counter           */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr04Read(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr04Read()  - T1 Low order counter read (%02x)",u6522Timer1.uCount.sW.tL));

   // Clear interrupt flag

   t6522IFLG&=(E6522IFLG_TIMER1^0xff);

   return(u6522Timer1.uCount.sW.tL);
}

T_UCHAR f6522Addr04Write(T_UWORD tAddress,T_UCHAR tData)
{
   fDebug(MID,("f6522Addr04Write() - T1 Low order latch write (%02x)",tData));
   u6522Timer1.uLatch.sW.tL=tData;
   return(u6522Timer1.uLatch.sW.tL);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr05Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 T1 high order counter                  */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr05Read(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr05Read()  - T1 High order counter read (%02x)",u6522Timer1.uCount.sW.tH));
   return(u6522Timer1.uCount.sW.tH);
}


T_UCHAR f6522Addr05Write(T_UWORD tAddress,T_UCHAR tData)
{
   fDebug(MID,("f6522Addr05Write() - T1 High order latch write (%02x)",tData));
   u6522Timer1.uLatch.sW.tH=tData;
   u6522Timer1.uCount.tW=u6522Timer1.uLatch.tW;

   // Setup  timer modes if required

   switch (t6522AUX_T1CTRL)
   {
       case 2:             // ONE SHOT MODE ON PB7
           t6522ORB_7=0;
           break;
       case 3:             // FREE RUN MODE
           t6522ORB_7^=TMPL_RB_7;
           break;
       default:
           break;
   }
#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=RAMP_TEST_BIT;
   ramp_patch_cycle_countdown[ramp_patch_queue_depth]=RAMP_REACT_OFFSET_CYCLES;
   ramp_set_to[ramp_patch_queue_depth]=t6522ORB_7;
   ramp_patch_queue_depth++;

#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef SEQUENCER_ANALOG_CYCLE_PATCH

#else
 fAnalogTick();
#endif
 // Update analog hardware

 // Clear interrupt flag
 t6522IFLG&=(E6522IFLG_TIMER1^0xff);
 return(u6522Timer1.uLatch.sW.tH);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr06Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 T1 low order latches                   */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr06Read(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr06Read()  - T1 Low order latch read (%02x)",u6522Timer1.uLatch.sW.tL));
   return(u6522Timer1.uLatch.sW.tL);
}

T_UCHAR f6522Addr06Write(T_UWORD tAddress,T_UCHAR tData)
{
   fDebug(MID,("f6522Addr06Write() - T1 Low order latch write (%02x)",tData));
   u6522Timer1.uLatch.sW.tL=tData;
   return(u6522Timer1.uLatch.sW.tL);
}




/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr07Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 T1 high order latches                  */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr07Read(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr07Read()  - T1 High order latch read (%02x)",u6522Timer1.uLatch.sW.tH));
   return(u6522Timer1.uLatch.sW.tH);
}


T_UCHAR f6522Addr07Write(T_UWORD tAddress,T_UCHAR tData)
{
   fDebug(MID,("f6522Addr07Write() - T1 High order latch write (%02x)",tData));
   u6522Timer1.uLatch.sW.tH=tData;
   return(u6522Timer1.uLatch.sW.tH);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr08Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 T2 low order latches/counters          */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr08Read(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr08Read()  - T2 Low order counter read (%02x)",u6522Timer2.uCount.sW.tL));

   // Clear interrupt flag

   t6522IFLG&=(E6522IFLG_TIMER2^0xff);

   return(u6522Timer2.uCount.sW.tL);
}


T_UCHAR f6522Addr08Write(T_UWORD tAddress,T_UCHAR tData)
{
   fDebug(MID,("f6522Addr08Write() - T2 Low order latch write (%02x)",tData));
   u6522Timer2.uLatch.sW.tL=tData;
   return(u6522Timer2.uLatch.sW.tL);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr09Read/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 T2 high order counter                  */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr09Read(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr06Read()  - T2 High order counter read (%02x)",u6522Timer2.uCount.sW.tH));
   return(u6522Timer2.uCount.sW.tH);
}

T_UCHAR f6522Addr09Write(T_UWORD tAddress,T_UCHAR tData)
{
   fDebug(MID,("f6522Addr09Write() - T2 High order counter write (%02x)",tData));
   u6522Timer2.uCount.sW.tH=tData;
   u6522Timer2.uCount.sW.tL=u6522Timer2.uLatch.sW.tL;
   bTimer2OneShot=T_TRUE;

   // Clear interrupt flag

   t6522IFLG&=(E6522IFLG_TIMER2^0xff);

   return(u6522Timer2.uCount.sW.tH);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr0ARead/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 Shift register                         */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr0ARead(T_UWORD tAddress)
{
   fDebug(MID,("f6522Addr0ARead()  - Shift register read (%02x)",t6522SHFTREG));
   // Clear interrupt flag
   t6522IFLG&=(E6522IFLG_SHFT^0xff);
   return(t6522SHFTREG);
}


T_UCHAR f6522Addr0AWrite(T_UWORD tAddress,T_UCHAR tData)
{
   t6522SHFTREG=tData;
   t6522SHFTREGACT=8;

   fDebug(MID,("f6522Addr0AWrite()  - Shift register write (%02x)",t6522SHFTREG));

   // Clear interrupt flag
   t6522IFLG&=(E6522IFLG_SHFT^0xff);
#ifdef PATCH_OFFSET
 if (wait_ramp==T_WAIT_RAMP_ACCESS)
 {
  lSIGDEF_XOUTPUT-=lXSampleHold*PATCH_DELAY;
  lSIGDEF_YOUTPUT-=lYSampleHold*PATCH_DELAY;
  wait_ramp=T_WAIT_WAS_PATCHED;
 }
#endif
   return(t6522SHFTREG);
}



/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr0BRead/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 Auxiliary control register             */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr0BRead(T_UWORD tAddress)
{
   T_UCHAR tTmp;

   tTmp=(t6522AUX_T1CTRL<<6) | (t6522AUX_T2CTRL<<5) | (t6522AUX_SHFTCTRL<<2) | (t6522AUX_PB_LE<<1) | t6522AUX_PA_LE;

   fDebug(MID,("f6522Addr0BRead()  - Aux control register read (%02x)",tTmp));

   return(tTmp);
}


T_UCHAR f6522Addr0BWrite(T_UWORD tAddress,T_UCHAR tData)
{
   fDebug(MID,("f6522Addr0BWrite() - Aux control register write (%02x)",tData));

   t6522AUX_T1CTRL=(tData>>6)&3;
   t6522AUX_T2CTRL=(tData>>5)&1;
   t6522AUX_SHFTCTRL=(tData>>2)&7;

   // If we've switched to one-shot then PB7 must be set
   if ((t6522AUX_T1CTRL&0x02))
    t6522ORB_7=TMPL_RB_7;
   else
    t6522ORB_7=t6522ORB_7REG;
#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=RAMP_TEST_BIT;
   ramp_patch_cycle_countdown[ramp_patch_queue_depth]=RAMP_REACT_OFFSET_CYCLES;
   ramp_set_to[ramp_patch_queue_depth]=t6522ORB_7;
   ramp_patch_queue_depth++;

#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef SEQUENCER_ANALOG_CYCLE_PATCH

#endif

   // Check for an invalid shift mode
   if(t6522AUX_SHFTCTRL==3 || t6522AUX_SHFTCTRL==7)
   {
    fDebug(VERROR,("f6522Addr0BRead() - Bad shiftregister mode selected"));
   }

   t6522AUX_PB_LE=(tData>>1)&1;
   t6522AUX_PA_LE=tData&1;
#ifdef PATCH_OFFSET
   // chris test
   if (t6522AUX_SHFTCTRL==6)
   {
    wait_ramp=T_WAIT_SHIFTING;
   }
   else
    wait_ramp=T_WAIT_NOT;
#endif
   return(tData);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr0CRead/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 Peripheral control register            */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr0CRead(T_UWORD tAddress)
{
   T_UCHAR tTmp;

   tTmp=(t6522PCR_CB2CTRL<<5) | (t6522PCR_CB1CTRL<<4) | (t6522PCR_CA2CTRL<<1) | t6522PCR_CA1CTRL;

#ifdef DEBUG_MSG
   if (t6522PCR_CA1CTRL)
    fDebug(HIGH,("f6522Addr0CRead()  - Periperal control register read (%02x)",tTmp));
#endif

   return(tTmp);
}


T_UCHAR f6522Addr0CWrite(T_UWORD tAddress,T_UCHAR tData)
{
#ifdef DEBUG_MSG
   if (tData&1)
    fDebug(HIGH,("f6522Addr0CWrite() - Peripheral control register write (%02x)",tData));
#endif

   t6522PCR_CB2CTRL=(tData>>5)&7;
   t6522PCR_CB1CTRL=(tData>>4)&1;
   t6522PCR_CA2CTRL=(tData>>1)&7;
   t6522PCR_CA1CTRL=tData&1;

   switch(t6522PCR_CB2CTRL)
   {
       case 6:
           t6522CB2=0;
//if (enable_event)
//printf("\nEMU6522 t6522CB2 = 0");
           break;
       case 7:
//if (enable_event)
//printf("\nEMU6522  t6522CB2 = 1");
           t6522CB2=1;
           break;
       default:
           fDebug(VERROR,("f6522Addr0CWrite() - Illegal CB2 control mode %d",t6522PCR_CB2CTRL));
           break;
   }
#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=BLANK_TEST_BIT;
   blank_patch_cycle_countdown[blank_patch_queue_depth]=BLANK_REACT_OFFSET_CYCLES;
   blank_set_to[blank_patch_queue_depth]=t6522CB2;
   blank_patch_queue_depth++;
#endif

   switch(t6522PCR_CA2CTRL)
   {
       case 6:
           t6522CA2=0;
           break;
       case 7:
           t6522CA2=1;
           break;
       default:
           fDebug(VERROR,("f6522Addr0CWrite() - Illegal CA2 control mode %d",t6522PCR_CA2CTRL));
           break;
   }
#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=ZERO_TEST_BIT;
   zero_patch_cycle_countdown[zero_patch_queue_depth]=ZERO_REACT_OFFSET_CYCLES;
   zero_set_to[zero_patch_queue_depth]=t6522CA2;
   zero_patch_queue_depth++;
#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef SEQUENCER_ANALOG_CYCLE_PATCH
#endif

 fAnalogTick();
 return(tData);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr0DRead/Write()                                   */
/*                                                                           */
/*   Author      : K.W / C.S.                                                */
/*                                                                           */
/*   Description : Read/Write to 6522 Interrupt flag register                */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr0DReadNoLightpen(T_UWORD tAddress)
{
   T_UCHAR tTmp=0;
   if (t6522IFLG&t6522IER)
    tTmp=0x80;
#ifdef DEBUG_MSG
   if (t6522IFLG&2)
    fDebug(MID,("f6522Addr0DRead()  - Interrupt Flag register read (read 0x2==CA1)(%02x)",tTmp));
#endif
   tTmp=tTmp|t6522IFLG;
   fDebug(MID,("f6522Addr0DRead()  - Interrupt Flag register read (%02x)",tTmp));
   return(tTmp);
}

T_UCHAR f6522Addr0DReadLightpen(T_UWORD tAddress)
{
 T_UCHAR tTmp=0;
 if (vesa_mouse_button)
  fAnalogTick();

 if (t6522IFLG&t6522IER)
  tTmp=0x80;

#ifdef DEBUG_MSG
 if (t6522IFLG&2)
  fDebug(MID,("f6522Addr0DRead()  - Interrupt Flag register read (read 0x2==CA1)(%02x)",tTmp));
#endif

 tTmp=tTmp|t6522IFLG;
 fDebug(MID,("f6522Addr0DRead()  - Interrupt Flag register read (%02x)",tTmp));
 return(tTmp);
}


T_UCHAR f6522Addr0DWrite(T_UWORD tAddress,T_UCHAR tData)
{
// tAddress=0; // Stop compiler warning
   fDebug(MID,("f6522Addr0DWrite()  - Interrupt Flag register write (%02x)",tData));
   t6522IFLG&=(tData^0xff);
   return(tData);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr0ERead/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 Interrupt enable register              */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr0ERead(T_UWORD tAddress)
{
   T_UCHAR tTmp;

// tAddress=0; // Stop compiler warning

   tTmp=0x80 | t6522IER;

// tTmp=(1<<7) | (t6522IER_TIMER1<<6) | (t6522IER_TIMER2<<5) | (t6522IER_CB1<<4);
// tTmp|=tTmp  | (t6522IER_CB2<<3) | (t6522IER_SHFT<<2) | (t6522IER_CA1<<1) | t6522IER_CA2;

   fDebug(MID,("f6522Addr0ERead()  - Interrupt Enable register read (%02x)",tTmp));

   return(tTmp);
}


T_UCHAR f6522Addr0EWrite(T_UWORD tAddress,T_UCHAR tData)
{
// tAddress=0; // Stop compiler warning

//   fDebug(HIGH,("f6522Addr0EWrite()  - Interrupt Enable register write (%02x)",tData));

#ifdef DEBUG_MSG
   if (tData&E6522IFLG_CA1) // CA1 == Lightpen
   {
    fDebug(MID,("f6522Addr0EWrite()  - CA1 Interrupt Enable register write (%02x)",tData));
   }
#endif
   if (tData&0x80)
   {
    // Hi bits enable the relevant IE
    t6522IER|=(tData&0x7f);
   }
   else
   {
    // Hi bits disable the relevant IE
    // fixme
    if (bGblLightpenEnable==T_TRUE)
     t6522IER&=((tData&0x7f)^(0xff-2));
    else
     t6522IER&=((tData&0x7f)^(0xff));
    /* -2 for artmaster 1 only, since the disable CA1 is done */
    /* by clearing d00e, which is not the way it should be done */
    /* this patch should not cause any trouble with anything else */
   }
   return(tData);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6522Addr0FRead/Write()                                   */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Read/Write to 6522 Input/Output regster A*                */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_UCHAR f6522Addr0FRead(T_UWORD tAddress)
{
 T_UCHAR   tData;
 tData=t6522ORA&t6522DDRA;           // Add output bits
 tData|=t6522IRA&(t6522DDRA^0xff);   // Add input bits
 fDebug(MID,("f6522Addr0FRead()  - Input/Output register A read (%02x)",tData));
 return(tData);
}


T_UCHAR f6522Addr0FWrite(T_UWORD tAddress,T_UCHAR tData)
{
   t6522ORA=tData;

   fDebug(MID,("f6522Addr0FWrite() - Input/Output register A write (%02x)",tData));

#ifdef ANALOG_CYCLE_PATCH
   patch_must_be_applied|=DAC_TEST_BIT;
   dac_patch_cycle_countdown[dac_patch_queue_depth]=DAC_REACT_OFFSET_CYCLES;
   dac_set_to[dac_patch_queue_depth]=t6522ORA;
   dac_patch_queue_depth++;
#define SEQUENCER_ANALOG_CYCLE_PATCH
#include "pia.cc"
#undef SEQUENCER_ANALOG_CYCLE_PATCH
#endif
//   fAnalogTick();
//   fSoundTick();

   return(tData);
}
#endif //#ifndef _NO_DEBUG_INFORMATION_
