/**************************************************************************************\
*                                                                                      *
*               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                     *
*                                                                                      *
*                                                                                      *
*                                                                                      *
*      Global externed variables, macros, macro constants, and function prototypes.    *
*                                                                                      *
*   ---------------------------------------------------------------------------------  *
*                                                                                      *
*   Yes, this is ugly, yes, it's not quite standard practice, but there is madness to  *
*   method.  ;-)                                                                       *
*                                                                                      *
*   1. Include all the needed include files.                                           *
*   2. Define macro fn's and constants used elsewhere                                  *
*   3. define type definitions                                                         *
*   4. define externed global variables                                                *
*   5. define fn extern or local prototypes (self checking)                            *
*                                                                                      *
\**************************************************************************************/

#undef  DEBUG

#undef DEBUG
// This should always be on, but we can cheat for a slight speedup to turn it off?
#define CHECKODDPOINTERS 1
#define DEBUGLEVEL 100



//Enable to build a Lisa1 emulator instead of a Lisa2 emulator - not yet implemented - place holder.
//#define LISA1

// enables MMU cache vs mmu registers testing - this is VERY VERY SLOW, and no longer valid
//#define MMUVALIDATE 1


// If this is disabled the Generator CORE will calculate the status flags on every opcode
// hack for LisaEm to see if there are flag calculation issues.
#define NORMAL_GENERATOR_FLAGS 1

// This forces each executed opcode to have it's IPC re-created - used to see if IPC cache
// isn't working properly, or if we're hitting self-modifying code  -- very slow, do not use
//#define EVALUATE_EACH_IPC 1

//enable a read after write to ensure we get back the same data we wrote - no longer supported
//#define VERIFY_WRITES 1
// If this is enabled, it's a little slower because extra checks are required.

//do not use this ever//#define ALLOW_1536K_RAM 1 -- no longer


// Enable this if you want all of the Lisa Status register bits to be set. - slower, but more acurate.
#define FULL_STATREG 1

// Enable this to disassemble skipped opcodes to the log that weren't executed - might be buggy!
//#define DISASM_SKIPPED_OPCODES 1

// Same as above, but specific to a single block of code instead of every chunk of code.
// //0xd27a-0xddff for LisaTest  *REMOVE*
//#define LOOKAHEAD 1
//#define LOOKSTARTADDR    0x00b848d0
//#define LOOKENDADDR      0x00b849cc

// If enabled, what screenhash value to turn debugging on
//#define DEBUG_ON_SCREENHASH  {0,0,0,0,0,0,0,0,       0x7f,0x19,0xcc,0x88,0x87,0x5f,0xca,0x64,0xff,0xfc,0xff,0x5c,0x00,0x00}
//#define DEBUG_OFF_SCREENHASH {0,0,0,0,0,0,0,0,       0xff,0xff,0x9b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xdf}

//{0x7f,0xcb,0xe7,0xbd,0xe0,0xf3,0x2b,0xcd,0x7f,0xf3,0xff,0x5d,0x00,0x00}

// How close do we need to be in order to declare a matching the screen hash?
#define SCREENHASH_LIMIT    16

// Do read-only memory violations cause bus errors?
#define ROMEMCAUSESBUSERROR 1

// Do physical memory over/underflows cause MMU exceptions?
//#define PHYS_UNDER_BUSERR 1
//#ifdef PHYS_OVERFLOW_BUSERR 1

// Enable this to avoid C compiler assumptions (noteably in the get_pending_vector() fn)
// it's safer to enable this if not using GCC, or you can't guarantee expression evaluation order is left to right
#define PARANOID 1


// The following options are only for DEBUG enabled compiles
#ifdef DEBUG

// If this is enabled, and debug log is enabled, it will attempt to suppress loop disassembly
// by keeping track of the last MAX_LOOP_REGS and will only output the changed registers.
#define SUPPRESS_LOOP_DISASM 1
#define MAX_LOOP_REGS 10


// switches to fn's that log memory calls, if undefined, these are macros, so they're much faster.
// only turn this on if you need it.
//#define DEBUGMEMCALLS 1

// If this is enabled, it will force the Instruction Parameter Cache to be invalidated on
// for that address on each write to memory.  This is to correct problems with self-modifying code
// I'm not sure whether or not there are any such problems, but it is provided as a compile itme option.
//#define FORCE_MEMWRITE_TO_INVALIDATE_IPC 1

// If debugging is turned on, this option can be turned on to provide a dump of the
// instruction cache and also the current cpu clock value when debugging is enabled.
//#define ICACHE_DEBUG 1

// Detect procedure entry into LisaOS

#define PROCNAME_DEBUG 1

#endif

//-----------------------------------------------------------------------------------------------------------------------------

#ifndef IN_VARS_H
#define IN_VARS_H 1

#define BIT0  1
#define BIT1  2
#define BIT2  4
#define BIT3  8
#define BIT4  16
#define BIT5  32
#define BIT6  64
#define BIT7  128

#define BIT8  256
#define BIT9  512
#define BIT10 1024
#define BIT11 2048
#define BIT12 4096
#define BIT13 8192
#define BIT14 16384
#define BIT15 32768


// Allow C to call C++

#ifdef __cplusplus
#define CPP2C "C"
#else
#define CPP2C
#endif


// Magic Macros - allows me to get around one of C's more annoying limits
// global variables are generally a big no-no, but in emulators, you want
// to get as much performance out of things as you can, so you bend the rules.
//
// Globals accessed by other .c files need extern declarations, which is
// fine and great.  But externs stupidly don't ignore assignments, so you
// can't just use a global variable file, so you wind up with a .c and a .h
// if these get out of sync, all sorts of evil things can happen.  i.e. you
// delcare a variable as a uint8 in one file and a uint16 in another.  When
// you compile, the compiler has no knowledge that one .c file expencts a
// byte and the other expects a word - because the two .c files have a different
// view of things - one has the actual variable, the other has an extern
// delcaration - hence, very bad things happen.
//
// Solution: we fix this by putting all the global variables in a single file
// this one, but use C MACRO's to allow it to turn on extern in the case of
// the include, and assign in the value in the case of the globals vars.c file.
//
// Neat, no?
//
// The one caveat is that C Macro's can't handle missing parameters, so we need
// two versions - one for when we don't assign a value (DECLARE) and one for when
// we do (GLOBAL).  Also, we can't do this: int a,b,c - need one GLOBAL per var now.
//- - - - - - - - - -

///////////////////////////////////////////////////////////////////////////////////
// Are we assigning a value to the variable? (and alternate default value version)


//#define    ASSIGN(TYPE, VAR, val...)        TYPE VAR= ## val  // ## causes gcc 3.x preprocessor to warn
#define    ASSIGN(TYPE, VAR, val...)        TYPE VAR = val
#define   CASSIGN(MYTYPE, MYVAR, val...)    const MYTYPE MYVAR = val
#define  NOASSIGN(TYPE, VAR)                TYPE VAR

// Are we defining an extern reference to the variable?
#define  REFERENCE(TYPE, VAR, val...)  extern TYPE VAR
#define CREFERENCE(TYPE, VAR, val...)  extern const TYPE VAR

// Doesn't matter, we can use a single macro for both, but decide which one here.
#ifdef IN_VARS_C

  #define GLOBAL(TYPE, VAR, val...)           TYPE VAR = val
  #define DECLARE(TYPE, VAR)                  TYPE VAR
  #define AGLOBAL(MYTYPE, MYVAR, val...)     const MYTYPE MYVAR = val
  #define ACGLOBAL(TYPE, VAR, val...)        const TYPE VAR = val

#else
  #define AGLOBAL  REFERENCE
  #define ACGLOBAL REFERENCE
  #define GLOBAL   REFERENCE
  #define DECLARE  REFERENCE
#endif


/////////////////////////////////////////////////////////////////////////////////


// include all the includes we'll (might) need (and want)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#ifndef __MSVCRT__
#include <sys/mman.h>
#endif


//#include "extra-defines.h"
#include "generator.h"
#include "registers.h"


// disable this - dangerous to little-endian transforms??
#ifdef ALIGNLONGS
#undef ALIGNLONGS
#endif



#include "z8530_structs.h"
#include "libdc42.h"


// If the Host OS has this, use it.
#ifndef FILENAME_MAX
 #define FILENAME_MAX 256
#endif


/*-------------------- 2003.07.08 17:23 ------------------------
 * hack to fix endianness under CygWin.  Might not be an
 * actuall issue with cygwin, but rather with the configure
 * scripts that I use...  *NOTE* Modifications to these must
 * also be reflected in registers.h and generator.h!
 * ----------------------------------------------------------*/

#ifdef PROCESSOR_INTEL
  #undef WORDS_BIGENDIAN
  #undef BIG_ENDIAN
  #ifndef LITTLE_ENDIAN
    #define LITTLE_ENDIAN 1
  #endif
  #undef BYTESHIGHFIRST
#endif

#ifdef  PROCESSOR_SPARC
  #define WORDS_BIGENDIAN 1
  #ifndef BIG_ENDIAN
    #define BIG_ENDIAN 1
  #endif
  #undef  LITTLE_ENDIAN
  #define BYTESHIGHFIRST 1
#endif

#ifdef  __POWERPC__
#define BYTES_HIGHFIRST  1
#define WORDS_BIGENDIAN  1
#endif
#ifdef __sparc__
#define BYTES_HIGHFIRST  1
#define WORDS_BIGENDIAN
#endif
#ifdef sparc
#define BYTES_HIGHFIRST  1
#define WORDS_BIGENDIAN  1
#endif



#ifdef __CYGWIN__
  #undef WORDS_BIGENDIAN
  #undef BIG_ENDIAN
  #ifndef LITTLE_ENDIAN
    #define LITTLE_ENDIAN 1
  #endif
  #undef BYTESHIGHFIRST
#endif





// Utility tables
//
// These are here to make certain transformation operations faster, and easier.
//
// Doesn't look like I'm using most of these, but it may be worth having them around
//
//
//////////////////////////////////////////////////////////////////////////////////

// given a byte, find the bit# with the highest value.  return ff for 0 since
// no bit is set (bit0=1, bit1=2, bit2=4, bit3=8, etc.)
static inline int highest_bit_num(uint8 v)
{
    unsigned int s, r = 0;
    if (v == 0) return 0xff;
    s = ((v & 0xf0)!=0) << 2; v >>= s; r |= s;
    s = ((v & 0x0c)!=0) << 1; v >>= s; r |= s;
    s = ((v & 0x02)!=0) << 0; v >>= s; r |= s;
    return r;
}

// same as above but instead, return the value of the highest bit, not it's #
ACGLOBAL(uint8,highest_bit_val[],
{ 0x00,0x01,0x02,0x02,0x04,0x04,0x04,0x04,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
  0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
  0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
});

// same as above but invert the result (to save an ^0xff operation on masks)
ACGLOBAL(uint8,highest_bit_val_inv[],
{ 0xff,0xfe,0xfd,0xfd,0xfb,0xfb,0xfb,0xfb,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,
  0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,
  0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,
  0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,
  0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,
  0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,
  0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,
  0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f
});





/////////////////////////////////////  Macro Constants ////////////////////////////////////////////////////////////////////////



//////
// Used to decode MMU SLR
//                                8    4    2   1
#define FILTR           0xf00 //(2048+1024+512+256)
#define SLR_MASK        0xf00 //(2048+1024+512+256)  // f
#define SLR_RO_STK      0x400 //(     1024        )  // 4
#define SLR_RO_MEM      0x500 //(     1024+    256)  // 5
#define SLR_RW_STK      0x600 //(     1024+512    )  // 6
#define SLR_RW_MEM      0x700 //(     1024+512+256)  // 7
#define SLR_IO_SPACE    0x900 //(2048+         256)  // 8
#define SLR_UNUSED_PAGE 0xc00 //(2048+1024)          // c   1100= IO+RO (Read Only + IO)
#define SLR_SIO_SPACE   0xf00 //(2048+1024+512+256)  // f

#define SERIAL_PORT_A_DATA    0xFCD247
#define SERIAL_PORT_A_CONTROL 0xFCD243
#define SERIAL_PORT_B_DATA    0xFCD245
#define SERIAL_PORT_B_CONTROL 0xFCD241
#define IRQ_FLOPPY     1			// run of the mill floppy IRQ's.
#define IRQ_VIDEO      1            // not sure if this is correct
#define IRQ_FDIR_ON    40           // special cases.  These are for floppy fdir=1, fdir=0
#define IRQ_FDIR_OFF   41
#define IRQ_GOBYTE_0   42           // zero gobyte after some time

#define IRQ_SCC        6            // Serial port
#define IRQ_VIA1       2			// Keyboard/Mouse/Clock (COPS controller)
#define IRQ_COPS       2            // Keyboard/Mouse/Clock (COPS controller)
#define IRQ_VIA2       1 			// Parallel Port VIA
#define IRQ_SLOT0      5			// Expasion Slot IRQ's
#define IRQ_SLOT1      4
#define IRQ_SLOT2      3

/*
*   7   NMI - Highest Priority                                                         *
*   6   RS-232 Ports                                                                   *
*   5   Expansion Slot 0                                                               *
*   4   Expansion Slot 1                                                               *
*   3   Expansion Slot 2                                                               *
*   2   Keyboard                                                                       *
*   1   All other internal interrupts -- lowest priority                               *
*                                                                                      *
*   Reset: Initial SSP               $000000           0                               *
*   Reset: Initial PC                $000004           1                               *
*   Bus Error:                       $000008           2                               *
*   Address Error:                   $00000C           3                               *
*   Illegal Instruction:             $000010           4                               *
*   Zero Divide:                     $000014           5                               *
*   CHK Instruction:                 $000018           6                               *
*   TRAPV Instruction:               $00001C                                           *
*   Privilidge Violation:            $000020                                           *
*   Trace:                           $000024                                           *
*   Unimplemented Instruction 1010   $000028                                           *
*   Unimplemented Instruction 1111   $00002C                                           *
*   Reserved/Unassigned:             $000030 - $00005F                                 *
*   Spurious Interrupt:              $000060           24                              *
*   Other Internal Interrupt:        $000064                                           *
*   Keyboard Interrupt:              $000068           1a/26                           *
*   Slot 2 Autovector:               $00006C           1b/27                           *
*   Slot 1 Autovector:               $000070           1c/28                           *
*   Slot 0 Autovector:               $000074           1d/29                           *
*   RS-232 Interrupt                 $000078           1e/30                           *
*   Non-Maskable Interrupt:          $00007C           1f/31                           *
*   Trap Instruction Vectors:        $000080 - $000BF                                  *
*   Reserved, Unassigned:            $0000C0 - $000Cf                                  *
*   User Interrupt Vectors:          $000100 - $003FF                                  *

*/

// this must be a power of 2 under 65536 and huge!  This is the size of the Interrupt Queue Ring buffer.
// since the lisa can shut off interrupts,  we need this to be huge.
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#define MAXIRQQUEUE 64


// *** WARNING Make sure you copy the above to vars.c as
// it does not include vars.h
#define PROFILE_IMG_HEADER_SIZE 2048

/* Defines for the Via 6522 code -- MMU needs these to decypher the register accessed. */
// Expansion Port Slots.  PARPORTVER is the ROM version number.
#define PARPORTVER  {0x00,01,00,07}
#define V0HVIA1BASE 0xFC2000
#define V0LVIA1BASE 0xFC2800
#define V1HVIA1BASE 0xFC4000
#define V1LVIA1BASE 0xFC4800
#define V2HVIA1BASE 0xFC8000
#define V2LVIA1BASE 0xFC8800

/* Definitions for VIA 1   -- COPS                                      */
#define VIA1BASE 0xFCDD80             /* Base address of VIA 1          */

// VIA1 registers are on the odd addresses in increments of 2.
#define ORB1   ((0*2)+1)    /* Port B output Register         */
#define IRB1   ((0*2)+1)
#define ORA1   ((1*2)+1)    /* Port A output Register         */
#define IRA1   ((1*2)+1)
#define DDRB1  ((2*2)+1)    /* Port B Data Direction Register */
#define DDRA1  ((3*2)+1)    /* Port A Data Direction Register */
#define T1CL1  ((4*2)+1)
#define T1CH1  ((5*2)+1)
#define T1LL1  ((6*2)+1)    /* Low Order T1 Latch             */
#define T1LH1  ((7*2)+1)    /* High Order T1 Latch            */
#define T2CL1  ((8*2)+1)    /* Low Order T2 Counter           */
#define T2CH1  ((9*2)+1)    /* Low Order T2 Counter           */
#define SR1    ((10*2)+1)
#define ACR1   ((11*2)+1)
#define PCR1   ((12*2)+1)
#define IFR1   ((13*2)+1)
#define IER1   ((14*2)+1)
#define ORANH1 ((15*2)+1)
#define IRANH1 ((15*2)+1)


#define VVIA2BASE 0xFCD900             /* Base address of VIA 2          */

/* Definitions for VIA 2   -- Parallel Port  */
// VIA2 registers are on the odd addresses in increments of 8.
#define ORB2   ((0*8)+1)
#define IRB2   ((0*8)+1)
#define ORA2   ((1*8)+1)
#define IRA2   ((1*8)+1)
#define DDRB2  ((2*8)+1)
#define DDRA2  ((3*8)+1)
#define T1CL2  ((4*8)+1)
#define T1CH2  ((5*8)+1)
#define T1LL2  ((6*8)+1)
#define T1LH2  ((7*8)+1)
#define T2CL2  ((8*8)+1)
#define T2CH2  ((9*8)+1)
#define SR2    ((10*8)+1)
#define ACR2   ((11*8)+1)
#define PCR2   ((12*8)+1)
#define IFR2   ((13*8)+1)
#define IER2   ((14*8)+1)
#define ORANH2 ((15*8)+1)
#define IRANH2 ((15*8)+1)


#define ORB    0
#define IRB    0
#define ORA    1
#define IRA    1
#define DDRB   2
#define DDRA   3
#define T1CL   4
#define T1CH   5
#define T1LL   6
#define T1LH   7
#define T2CL   8
#define T2CH   9
#define SHIFTREG    10
#define ACR   11
#define PCR   12
#define IFR   13
#define IER   14
#define ORANH 15
#define IRANH 15

// Shadow of T2
#define T2LL   16
#define T2LH   17

// Shadows of I/O regs
#define IRAA  18
#define ORAA  19
#define IRBB  20
#define ORBB  21


// Paralell port VIA PORT B bit definitions
#define OCDLine_BIT    1
#define BSYLine_BIT    2
#define DENLine_BIT    4
#define RRWLine_BIT    8
#define CMDLine_BIT   16
#define PARITY_BIT    32
#define DSK_DIAG_BIT  64
#define CTRL_RES_BIT 128



#define  VIA_IRQ_BIT_CA2          1  // cleared by read/write of reg1 (ora) unless CA2/CB2 in PCR set as independent irq - only writing to ifr will then clear it
#define  VIA_IRQ_BIT_CA1          2  // cleared by read or write reg 1
#define  VIA_IRQ_BIT_SR           4  // cleared by read/write of shift register
#define  VIA_IRQ_BIT_CB2          8  // cleared by read or write orb - except if PCR sets it as independent IRQ like ca2
#define  VIA_IRQ_BIT_CB1         16  // cleared by read/write orb
#define  VIA_IRQ_BIT_T2          32  // read t2 low or write t2 high clears it
#define  VIA_IRQ_BIT_T1          64  // read t1 low or wite t1 high clears it
#define  VIA_IRQ_BIT_SET_CLR_ANY 128 // only cleared when all other IRQ's are cleared.

/* Timer ID's  */
#define CYCLE_TIMER_VIAn_T1_TIMER(x)  ((x)    )
#define CYCLE_TIMER_VIAn_T2_TIMER(x)  ((x)+128)
#define CYCLE_TIMER_VIAn_SHIFTREG(x)  ((x)+64 )


#define CYCLE_TIMER_VIA1_T1_TIMER           (1    )
#define CYCLE_TIMER_VIA1_T2_TIMER           (1+128)
#define CYCLE_TIMER_VIA1_SHIFTREG           (1+64 )

#define CYCLE_TIMER_VIA2_T1_TIMER           (2    )
#define CYCLE_TIMER_VIA2_T2_TIMER           (2+128)
#define CYCLE_TIMER_VIA2_SHIFTREG           (2+64 )

#define CYCLE_TIMER_VIA3_T1_TIMER           (3    )
#define CYCLE_TIMER_VIA3_T2_TIMER           (3+128)
#define CYCLE_TIMER_VIA3_SHIFTREG           (3+64 )

#define CYCLE_TIMER_VIA4_T1_TIMER           (4    )
#define CYCLE_TIMER_VIA4_T2_TIMER           (4+128)
#define CYCLE_TIMER_VIA4_SHIFTREG           (4+64 )

#define CYCLE_TIMER_VIA5_T1_TIMER           (5    )
#define CYCLE_TIMER_VIA5_T2_TIMER           (5+128)
#define CYCLE_TIMER_VIA5_SHIFTREG           (5+64 )

#define CYCLE_TIMER_VIA6_T1_TIMER           (6    )
#define CYCLE_TIMER_VIA6_T2_TIMER           (6+128)
#define CYCLE_TIMER_VIA6_SHIFTREG           (6+64 )

#define CYCLE_TIMER_VIA7_T1_TIMER           (7    )
#define CYCLE_TIMER_VIA7_T2_TIMER           (7+128)
#define CYCLE_TIMER_VIA7_SHIFTREG           (7+64 )

#define CYCLE_TIMER_VIA8_T1_TIMER           (8    )
#define CYCLE_TIMER_VIA8_T2_TIMER           (8+128)
#define CYCLE_TIMER_VIA8_SHIFTREG           (8+64 )

#define CYCLE_TIMER_VERTICAL_RETRACE        (11   )
#define CYCLE_TIMER_COPS_MOUSE_IRQ          (12   )
#define CYCLE_TIMER_COPS_CLOCK_DSEC         (13   )
#define CYCLE_TIMER_FDIR                    (14   )

#define CYCLE_TIMER_Z8530                   (15   )

#define CYCLE_TIMER_SCC_B_XMT_BUF_EMPTY     (16+0 )     // Z8530 Channel B Transmit Buffer Empty
#define CYCLE_TIMER_SCC_B_EXT_STAT_CHG      (16+1 )     // Z8530 Channel B External/Status Change
#define CYCLE_TIMER_SCC_B_RCVD_CHAR         (16+2 )     // Z8530 Channel B Receive Character Avail
#define CYCLE_TIMER_SCC_B_SPECIAL           (16+3 )     // Z8530 Channel B Special Receive Condition

#define CYCLE_TIMER_SCC_A_XMT_BUF_EMPTY     (20+0 )     // Z8530 Channel A Transmit Buffer Empty
#define CYCLE_TIMER_SCC_A_EXT_STAT_CHG      (20+1 )     // Z8530 Channel A External/Status Change
#define CYCLE_TIMER_SCC_A_RCVD_CHAR         (20+2 )     // Z8530 Channel A Receive Character Avail
#define CYCLE_TIMER_SCC_A_SPECIAL           (20+3 )     // Z8530 Channel A Special Receive Condition
















///////////////////////////////////////////////// Type definitions /////////////////////////////////////////////////
//
// 64 bit values might not be available on all host systems.  They seem to be define on modern ones, although I've
// noticed buggy/limited support for them when using shift operations.  However, as long as addition/substraction
// and multiplication works, and they're built in to your CPU, they can be used to gain an advantage with the timer
// code.  int32's can also be used by the timer code, however they will cause a slowdown every 5 minutes of guest
// runtime, and at every event as the timers are checked for overflow.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef int64
  #define int64 int64_t
  #define USE64BITTIMER 1
#endif
#define USE64BITTIMER 1


// HALF_CLK needs to be the highest bit we can go before the value becomes negative. i.e. for 32 bit values, bit 30.
// for 64 bit values, bit 62 (since the msb is the sign bit)
//
//------------------------------------------------------------------------------------------------------------------------
//
// I'd love to change these to int64's and HALF_CLK to (1<<62), however, it seems 64 bit shifts are a bit buggy at the moment
// on Linux IA32 with debian gcc 4.0.3-1

//#ifdef XXBROKENXX
#ifdef USE64BITTIMER
                  //  0123456789012345 - careful, want to use 1<<62 however, found bugs in shifting with gcc 4!
  #define HALF_CLK (0x4000000000000000)
  #define XTIMER int64
 // #define prevent_clk_overflow_now(x) {1}
 // #define prevent_clk_overflow(x) {1}
  #define USING64BITTIMER 1

#else

  #define HALF_CLK (1<<30)
  #define XTIMER int32
  #define CLKDIV2(x) ((x)>>=1)
  //#define CLKDIV2(x) ((x)/=2)
extern void  prevent_clk_overflow_now(void);

#endif

extern void  init_ipct_allocator(void);

GLOBAL(uint8,*lisaram,NULL);                 // pointer to Lisa RAM



// this enables a hack that tricks the lisa into skipping the full ram test, thus speeding up
// the boot process - this sets a PRAM variable saying RAM test is done.
GLOBAL(int,cheat_ram_test,1);
// othe globally saved defaults
GLOBAL(int,sound_effects_on,1);
GLOBAL(int,powerfile_power,1);
DECLARE(int,skins_on);
DECLARE(int,skins_on_next_run);
DECLARE(int,lisa_ui_video_mode);



typedef uint8 lisa_mem_t;         /* type indicator for the above #defines for use with fn's           */

typedef struct
{
  uint32 size;
  uint8 *buffer;
  uint32 start;
  uint32 end;
} FLIFLO_QUEUE_t;

typedef struct
      {
       int16 x;
       int16 y;
       int8  button;                    // 0=no click change, 1=down, -1=up.
      } mousequeue_t;




typedef struct
{
    int8   Command;                      // what command is the profile doing:
                                         // -1=disabled, -2=idle, 1=read, 2=write, 3=write verify
                                         //
    uint8   StateMachineStep;            // what step of Command is the state machine of this profile in?

    uint8   DataBlock[4+8+532+8+2];      // 4 status bytes, command block, data block, 2 for good luck ;)

    uint16  indexread;                   // indeces into the buffer for the Lisa to Read or Write
	uint16  indexwrite;
    uint32  blocktowrite;                // used by the write command to store the block number to write

  //uint32  numblocks;                   // (24 bit value!) size of this profile in blocks.
                                         //   (9728=5mb, 532 bytes/sector)
                                         // We shouldn't make this more than 10Mb until we've tried it.

                                         // Control Lines from 6522 (except OCDLine which is Command=-1)
    uint8   CMDLine;                     // set by Lisa
    uint8   BSYLine;                     // set by ProFile
    uint8   DENLine;                     // set by Lisa (drive enabled)
    uint8   RRWLine;                     // set by Lisa (read or write)

    uint8   VIA_PA;                      // data to from VIA PortA (copied to/from V->via[0])
    uint8   last_a_accs;
    int32   last_reset_cpuclk;           // last reset occured at what cpu clock?

    DC42ImageType DC42;                  // actual storage container

    // DC42 contains the ProFilename and file handler
    //char  ProFileFileName[FILENAME_MAX]; // the file name for this Profile disk image to open;

    XTIMER   clock_e;                     // used for timeouts - this is in relation to cpu68k_clocks
    XTIMER   alarm_len_e;                 // used for timeouts - how long was the delay set for in clock_e event expiration

}  ProFileType;




typedef struct
{
	uint8 active;           		// is this VIA active? (except via1 and via2 s/b always active)
                                 	// make sure that the initialization code sets these anyway!!!

    uint8 vianum;                   // Which VIA is this?

    uint8 via[22];                  // standard via registers + timer 2 shadows and actual IRA/ORA/IRB/IRA shadows, etc.

    int last_a_accs;                // was the last access to port A a read or a write? (for DDRA flips from 00 to ff)
                                    // I've seen some code that writes to port A, then sets DDRA to FF, only at that point
                                    // is the data put on the port.  I've seen other code that does the opposite, so I need
                                    // some way to distinguish what the value in PORT A is from in order to output properly

    int orapending;                 // there are many ways to output data.  some OS's set DDRA=0, then write to ORA, then
                                    // set DDRA=FF to output.  Others set DDRA=FF 1st, then write to ORA.  When DDRA=0 and
                                    // a write is made to ora, the data cannot be placed on PA, but as soon as DDRA=FF, the
                                    // PA gets data out and CA2 is set.  So to avoid a bug where an extra ORA is made when
                                    // DDRA=FF, ORA is written, DDRA=0, then DDRA=FF, this keeps track of the pending.

    XTIMER t1_e;                    // e_clock trigger - at what point will the via clock expire vs cpu68k_clocks
    XTIMER t1_fired;
    XTIMER t2_e;
    XTIMER t2_fired;
    XTIMER sr_e;
    XTIMER sr_fired;

    //#ifdef DEBUG
    XTIMER t1_set_cpuclk;
    XTIMER t2_set_cpuclk;
    XTIMER t1_fired_cpuclk;
    XTIMER t2_fired_cpuclk;
    //#endif

    ProFileType *ProFile;           // If there's a ProFile attached, this structure deals with it.
    int ADMP;                       // If there's an Apple Dot Matrix Printer (same as IW, but parallel)

	uint8 irqnum;           		// Interrupt number for this VIA
	uint8 srcount;
    uint8 ca1, ca2, cb1, cb2;       // port A,B control lines

	uint8 (*irb)(uint8 vianum, uint8 reg);		    // Function Pointers to the Handlers for what's connected to the VIA's.
	void  (*orb)(uint8 vianum,uint8 data, uint8 reg);
	uint8 (*ira)(uint8 vianum, uint8 reg);
	void  (*ora)(uint8 vianum,uint8 data, uint8 reg);
}   viatype;

// What can I say, I'm a lazy fuck, I don't like to worry about the case of these.
#define ViaType viatype
#define VIAType viatype
#define VIAtype viatype

GLOBAL(int32,video_scan,0);

GLOBAL(int,lisa_vid_size_x,720);
GLOBAL(int,lisa_vid_size_y,364);
GLOBAL(int,lisa_vid_size_xbytes,90);
GLOBAL(int,has_lisa_xl_screenmod,0);

// used by mouse routines to detect mouse acceleration undo strategy
#define LISA_ROM_RUNNING      0
#define LISA_OFFICE_RUNNING   1
#define LISA_TEST_RUNNING     2
#define LISA_MACWORKS_RUNNING 3
#define LISA_MONITOR_RUNNING  4
#define LISA_XENIX_RUNNING    5
#define UNKNOWN_OS_RUNNING    100

GLOBAL(int,running_lisa_os,LISA_ROM_RUNNING);
int check_running_lisa_os(void);
GLOBAL(int,mouse_x_tolerance,0);
GLOBAL(int,mouse_y_tolerance,0);

GLOBAL(int,mouse_x_halfing_tolerance,1);
GLOBAL(int,mouse_y_halfing_tolerance,1);

// can turn these into a pointer and several arrays for various OS's.
GLOBAL(int,anti_jitter_sample_dec1[],{64,32,16,8,4,2,0,0,0});
GLOBAL(int,anti_jitter_sample_dec2[],{1,2,4,16,32,64,0,0,0});

GLOBAL(int,anti_jitter_decellerate_xt[],{8,32,64,0});
GLOBAL(int,anti_jitter_decellerate_xn[],{1,2,4,0});
GLOBAL(int,anti_jitter_decellerate_yt[],{8,32,64,0});
GLOBAL(int,anti_jitter_decellerate_yn[],{1,2,3,0});




GLOBAL(uint32,lisa_os_mouse_x_ptr,0x486);
GLOBAL(uint32,lisa_os_mouse_y_ptr,0x488);
GLOBAL(uint32,lisa_os_boot_mouse_x_ptr,0x486);
GLOBAL(uint32,lisa_os_boot_mouse_y_ptr,0x488);
GLOBAL(int8,floppy_picked,1);                         //2006.06.11 - if 1 enable profile access immediately

typedef struct _lisa_clock
{
 uint8 year;
 uint8 days_h;
 uint8 days_l;  uint8 hours_h;
 uint8 hours_l; uint8 mins_h;
 uint8 mins_l;  uint8 secs_h;
 uint8 secs_l;  uint8 tenths;
} t_lisa_clock;

DECLARE(t_lisa_clock,lisa_clock);

GLOBAL(int32,lisa_alarm,0);
GLOBAL(uint8,lisa_clock_set_idx,0);
GLOBAL(uint8,lisa_alarm_power,0);
GLOBAL(uint8,lisa_clock_on,1);
DECLARE(uint8,eparity[256]);
DECLARE(uint8,lisa_clock_set[8]);

// Instruction Parameter Cache
typedef struct _t_ipc {
    void (*function)(struct _t_ipc *ipc);  //8/4    // pointer to the function that executes this opcode
    uint8 used;                            //1      // bitmap of XNZVC flags inspected
    uint8 set;                             //1      // bitmap of XNZVC flags altered
    uint16 opcode;                         //2      // absolutely necessary - the opcode itself i.e. 0x4e75=RTS

    uint16 wordlen;                        //2      // might be able to delete this if we also add nextpc, but diss68k will need work as will
                                                    // lots of mods of cpu68.k  To get it call iib->wordlen  but the illegal instruction in
                                                    // there needs checking.

    unsigned int :0;                       //3      // what's this here for?  alignment I suspect?
    uint32 src;                            //4
    uint32 dst;                            //4

    // //  // // // // // // // // // // // // // these are extensions to the normal generator code in order to refine it, etc.

    uint16 reg;                            //2      // for cpu68k-inline idx_val macros/inlines replacing the bug that causes the
                                                    // high octet in PC (bits 31-24) to be filled, then causes negative PC on sign ext.
    uint8  clks;                           //1      // might be able to remove this if I can get this from iib without too much of a slowdown - maybe

    struct _t_ipc *next;                   //8/4    // next ipc in chain. we could get rid of this, but then things would run slower
                                                    // and we'd need to do a whole lot of more work to get things to work.
                                                    // Need to get rid of this, but have to redo stuff in cpu68k.c to do it.
    // //  // // // // // // // // // // // // // /////////////////////////////////////////////////////////////////////////////
} t_ipc;


typedef struct _t_ipc_table
{
	// Pointers to all the IPC's in this page.  Since the min 68k opcode is 2 bytes in size
	// the most you can have are 256 instructions per page.  We thus no longer need a hash table
	// nor any linked list of IPC's as this is a direct pointer to the IPC.  Ain't life grand?

    t_ipc ipc[256];                            // only need this, the rest I think is junk

	// These are merged together so that on machines with 32 bit architectures we can
	// save four bytes.  It will still save 2 bytes on 64 bit machines.
    union t
    {   uint32 clocks;                  // can I get rid of this one? - it's used in cpu68k.c - but can be gotten rid of

                                        // we still use the *next pointer to keep track of IPC's.
        struct _t_ipc_table *next;      // try to get rid of these as they're not really needed, only used for free list!
    } t;


#ifdef PROCESSOR_ARM
	void (*compiled)(struct _t_ipc *ipc);
	//uint8 norepeat;	// what's this do? this only gets written to, but not read.  Maybe Arm needs it?
#endif
} t_ipc_table;

//////////////////////////////////////////////////////////
//
// MMU Translation Table for page.  This provides function pointers to read/write handlers as well as address translation
// via the address offset (signed) integer which gets added to the address.
//
// The table is an array of 256's ipc's -- if NULL it hasn't been allocated for this page.  The table is a pointer to
// an element of a linked list of IPC tables.
//
// For a 2MB (fully loaded non-XL 4MB hacked up Lisa) you have upto: 2097152 bytes of RAM + 16384ROM -> that's
// upto 2113536 bytes maximum of executable code (most of it won't be executable.)
//
// In terms of 512 byte MMU pages, this is: 4128 pages.  Each ipc structure takes about 32 bytes * 256/page = 8K * 4128 pages
// we have a maximum of 32MB (it's much smaller than this since not all of the Lisa's memory will be IPC's.)
// Yup, this is one memory hungry emulator....  So we need decent memory management on the MMU+ipct's.
//
// Why 256 ipc's/page? Simple: smallest 68k opcode is 2 bytes, there are 512/page, so at most there are 256 ipc's/page.
// But because management of these is not trivial, we allocate 256 of them per page if they're used.
//
// Note that the IPC's point to the virtual, not physical pages.

typedef struct _mmu_trans_t
{	int32 address;	     /* quick ea translation. Just add to lower bits  - needs to be signed 	*/
    //uint32 sor9;
	lisa_mem_t readfn;   /* index to read and write fn's for that segment, that way I			*/
	lisa_mem_t writefn;  /* can have read only segments without doing special checking.		*/
	t_ipc_table *table;  /* Pointer to a table of IPC's or NULL if one hasn't been assigned.	*/
} mmu_trans_t;


// Lisa's MMU table.  This get's converted to mmu_trans table above on a per/page basis.
typedef struct
{
    uint16 sor, slr;          // real sor, slr
    //uint16 newsor, newslr;    // used when updating - won't change to this until both are written to.
	uint8  changed;   		  // this is a flag to let us know that an mmu segment has changed.
		                  	  // come back later to correct it. bit 0=newslr set, bit 1=newsor set.
} mmu_t;






GLOBAL(uint8,lastsflag,0);

GLOBAL(uint8,floppy_FDIR,0);
GLOBAL(uint8,floppy_6504_wait,1);
GLOBAL(uint8,floppy_irq_top,1);
GLOBAL(uint8,floppy_irq_bottom,1);  // interrupt settings (are floppies allowd to interrupt)
DECLARE(uint8,floppy_ram[2048]);

GLOBAL(uint32,mmudirty,0);
DECLARE(uint32,mmudirty_all[5]);


DECLARE(uint8,lisarom[0x4000]);              // space for the MC68000 ROM
DECLARE(uint8,dualparallelrom[2048]);           // rom space for the dual parallel card

DECLARE(uint8,dirtyvidram[32768]);

GLOBAL(uint32,segment1,0);                   // MMU related bits
GLOBAL(uint32,segment2,0);
GLOBAL(uint32,context,0);
GLOBAL(uint32,lastcontext,0);

GLOBAL(uint32,address32,0);                  // not sure that this is needed anymore
GLOBAL(uint32,address,0);
GLOBAL(uint32,mmuseg,0);
GLOBAL(uint32,mmucontext,0);
GLOBAL(uint32,transaddress,0);

// special memory latches toggled by i/o space addresses in the lisa.
GLOBAL(uint32,diag1,0);
GLOBAL(uint32,diag2,0);
GLOBAL(uint32,start,1);
GLOBAL(uint32,softmem,0);
GLOBAL(uint32,vertical,0);
GLOBAL(uint32,verticallatch,0);
GLOBAL(uint32,hardmem,0);
GLOBAL(uint32,videolatch,0x2f);
GLOBAL(uint32,lastvideolatch,0x2f);
GLOBAL(uint32,videolatchaddress,(0x2f*32768));
GLOBAL(uint32,lastvideolatchaddress,0x2f*32768);
GLOBAL(uint32,statusregister,0);
GLOBAL(uint32,videoramdirty,0);
GLOBAL(uint32,videoximgdirty,0);
GLOBAL(uint16,memerror,0);
GLOBAL(uint8,contrast,0xff); // 0xff=black 0x80=visible 0x00=all white
GLOBAL(uint8,volume,4); // 0x0e is the mask for this.
GLOBAL(long,*dtc_rom_fseeks,NULL);
GLOBAL(FILE,*rom_source_file,NULL);

GLOBAL(int,debug_log_enabled,0);
GLOBAL(FILE,*buglog,NULL);

#ifdef DEBUG
#ifdef DEBUG_ON_SCREENHASH
GLOBAL(uint8,debug_hash[],DEBUG_ON_SCREENHASH);
#endif
#ifdef DEBUG_OFF_SCREENHASH
GLOBAL(uint8,debug_hash_off[],DEBUG_OFF_SCREENHASH);
#endif
#endif




// hexadecimal conversion table table.
ACGLOBAL(char,*hex,"0123456789abcdef");



/****************** COPS.C definitions/vars visible to outside world... ************************************/

#define MAXCOPSQUEUE 512
#define MAXMOUSEQUEUE 16

GLOBAL(int16,copsqueuelen,0);
DECLARE(uint8,copsqueue[MAXCOPSQUEUE]);
GLOBAL(uint8, NMIKEY,0);
GLOBAL(uint8, cops_powerset,0);
GLOBAL(uint8, cops_clocksetmode,0);
GLOBAL(uint8, cops_timermode,0);
GLOBAL( int8, mouse_pending,0);
GLOBAL( int8, mouse_pending_x,0);
GLOBAL( int8, mouse_pending_y,0);
GLOBAL(int16, last_mouse_x,0);
GLOBAL(int16, last_mouse_y,0);
GLOBAL(int16, last_mouse_button,0);
GLOBAL(int16, mousequeuelen,0);
DECLARE(mousequeue_t,mousequeue[MAXMOUSEQUEUE]);


// How many percent of the current IPCT's should we allocate. ** MUST MATCH WHAT'S IN vars.c!!!!!!! ***
#define IPCT_ALLOC_PERCENT 20

// What's the maximum time's we'll call malloc?
#define MAX_IPCT_MALLOCS 8

// we should never need to even do more than the initial malloc if initial_ipcts=4128.
DECLARE(t_ipc_table,*ipct_mallocs[MAX_IPCT_MALLOCS]);

// size of each of the above mallocs - not really needed, but could be useful for debugging.
DECLARE(uint32,sipct_mallocs[MAX_IPCT_MALLOCS]);

DECLARE(t_ipc_table,*ipct_mallocs[MAX_IPCT_MALLOCS]);
DECLARE(uint32,sipct_mallocs[MAX_IPCT_MALLOCS]);
GLOBAL(uint32,iipct_mallocs ,0);
GLOBAL(uint32,ipcts_allocated,0);
GLOBAL(uint32,ipcts_used,0);
GLOBAL(uint32,ipcts_free,0);
GLOBAL(t_ipc_table,*ipct_free_head,NULL);
GLOBAL(t_ipc_table, *ipct_free_tail,NULL);

/* (2MB RAM max+ 16KROM)=2113536 bytes of potentially executable code divided by 512(bytes/mmu page) = 4128
*  ipc's page = maximum= 8256 ipct's is maximum - should not have to go above this ever.
*  this value is only for testing, until we test the LisaEM under heavy load to find the actual used number of ipct's
*  and lessen it to free things up.  remember, each ipct holds 256 ipcs plus extra info.  */
GLOBAL(uint32,initial_ipcts,4128);

                                        // 212,179 ->missing 18 lines! 18 lines is the entire retrace cycle!

#define CYCLES_PER_LINE           (212) //was212               //213       /* (720+176)/(20.375Mhz/5Mhz) .. =219.87 was 224*/
#define VISIBLE_LINE_CYCLES       (179) //180
#define FULL_FRAME_CYCLES         (CYCLES_PER_LINE*364)                    //-4330)   /* 364 lines visible  -17 added 2005.04.14 10:51am */
#define HALF_FRAME_CYCLES         (FULL_FRAME_CYCLES/2)
#define QUARTER_FRAME_CYCLES      (FULL_FRAME_CYCLES/4)
//#define VERT_RETRACE_ON           (450)                 //450   //-VERT_RETRACE_ON-250
#define VERT_RETRACE_CYCLES_X     ((CYCLES_PER_LINE*(380-364))) //-VERT_RETRACE_ON)  //-VERT_RETRACE_ON)   //2005.05.04 - change it to 16  was 15  /* 15 retrace lines  */
#define VERT_RETRACE_ON           (VERT_RETRACE_CYCLES_X/2)
#define VERT_RETRACE_CYCLES       (VERT_RETRACE_CYCLES_X/2)

//#define ONE_SECOND              5000000
#define ONE_SECOND                5093750

#define COPS_IRQ_TIMER_FACTOR     20375                    // was 20000

#define MILLIONTH_OF_A_SECOND    (ONE_SECOND/1000000)
#define HUN_THOUSANDTH_OF_A_SEC  (ONE_SECOND/100000)
#define TEN_THOUSANDTH_OF_A_SEC  (ONE_SECOND/10000)
#define THOUSANDTH_OF_A_SECOND   (ONE_SECOND/1000)
#define HUNDREDTH_OF_A_SECOND    (ONE_SECOND/100)
#define TENTH_OF_A_SECOND        (ONE_SECOND/10)

#define HALF_OF_A_SECOND         (ONE_SECOND/2)
#define THIRD_OF_A_SECOND        (ONE_SECOND/3)
#define QUARTER_OF_A_SECOND      (ONE_SECOND/4)
#define FIFTH_OF_A_SECOND        (ONE_SECOND/5)
#define EIGHTH_OF_A_SECOND       (ONE_SECOND/8)

#define REFRESHRATE (5000000/60)
// this should be 60Hz during refresh.   // 5000000/60 - the emulator doesn't do 60Hz refreshes so that it will run more
// efficiently on older machines.


// old versions of above - likely wrong
//#define FULL_FRAME_CYCLES    65520
//#define HALF_FRAME_CYCLES    32760
//#define QUARTER_FRAME_CYCLES 16380
//#define VERT_RETRACE_CYCLES   2700
//#define COPS_IRQ_TIMER_FACTOR     20000
//#define HUNDRETH_OF_A_SECOND      50000
//#define TENTH_OF_A_SECOND        500000
//#define ONE_SECOND              5000000

// number of CPU cycles between transmitting a character of the SCC and the count zero interrupt.
#define Z8530_XMIT_DELAY        1000

GLOBAL(XTIMER,lastrefresh,0);
GLOBAL(XTIMER,virq_start,FULL_FRAME_CYCLES);
GLOBAL(XTIMER,fdir_timer,-1);
GLOBAL(XTIMER,cpu68k_clocks_stop,ONE_SECOND);
GLOBAL(XTIMER,cpu68k_clocks,0);
GLOBAL(XTIMER,clktest,0);
GLOBAL(XTIMER,cops_event,-1);
GLOBAL(XTIMER,tenth_sec_cycles,TENTH_OF_A_SECOND);      // 10th of a second cycles.  5,000,000 cycles/sec so 500000 10ths/sec
GLOBAL(XTIMER,z8530_event,-1);
GLOBAL(XTIMER,cops_mouse,(COPS_IRQ_TIMER_FACTOR*4));



#define KBCOPSCYCLES 6350
                              // if mouse is enabled, next clock event is cops_mouse.
                              // if copsqueuelen - that means we have data, and either cops event is off, or it's further
                              // away, then set it closer.


#define SET_COPS_NEXT_EVENT(x) { cops_event=(cops_mouse ? (cpu68k_clocks+cops_mouse):-1);                             \
                                 if (copsqueuelen>0 && ((cops_event>(cpu68k_clocks+KBCOPSCYCLES)) || cops_event<0))   \
                                        cops_event=cpu68k_clocks+KBCOPSCYCLES;                                        \
                                 DEBUG_LOG(0,"SET_COPS_NEXT:copsqueuelen:%d cops_mouse:%ld cops_event:%016llx cpu68k_clk:%016llx \n", \
                                             copsqueuelen,cops_mouse, cops_event, cpu68k_clocks);                     \
                                }


                               //         ***** still need logic for when cops_event=-1 but there's now data to deal with
                               //                 i.e. need to make sure timer is turned on.  likely can change the send macro to check
                               //
                               //if (cops_event<0) SET_COPS_NEXT_EVENT(0);


GLOBAL(uint32,via_clock_diff,2);       // 2

// These should be external as they belong to generator
#ifndef IN_CPU68K_C
extern unsigned long cpu68k_frames;
extern unsigned long cpu68k_frozen;
extern int abort_opcode;
  #ifdef DEBUG
   extern int do_iib_check;

  #endif
#endif

// recheck these for correctness!

// 0x3100=12544
// X  =  100000/12544 [7.97193877551]
// Hmmm, seems it's better to use 8 as a timing factor


#define LISA2ECLKFACTOR  8 // 10 //( 7.750950) //8.117647058825 //.11764705882=5,5  83=5,7 //.1176470588=5,5  .1176470589=5,7  .117647058[7|5]=5,5 585=5,5  57=5,5 9=5,7 //.117647055=5,5  .11764706[5|3|1]=5,7 .11764706=5,7  .11764707=5,7  .11764705=5,5 .1176471=5,7 72=5,7  .1176470=5,5 .117647[3|5]=5,7  //.117648=5,7  //.117647=5,5 //.117649=5,7  //117645=5,5 //1176[3/4]=5,5 //1165=5,7// 1176=5,5 //.1178/7=5,7 // 1175=5,5 //118=5,7 //117=5,5 //.119=5,7 // 8.113/114/115=5,5 // 8.11=5,5 // 8.12=5,7 // 8.16,14=5,7// 8.18=5,7 // 8.20=5,7 // 8.1=5,5 //8.0=5,5 // 8.3 5,7 // 8.25=5,7 //  8.2=5,7 // 8.1=7,5  // 9 5,7 //7.9=5,5  //8=5.5  //7.8=5.5  //8             // 10  // 8
#define LISA1ECLKFACTOR  4 //( 3.263358)
//#define LISA1ECLKFACTOR (24.117647058825) //24.117647058825 //.11764705882=5,5  83=5,7 //.1176470588=5,5  .1176470589=5,7  .117647058[7|5]=5,5 585=5,5  57=5,5 9=5,7 //.117647055=5,5  .11764706[5|3|1]=5,7 .11764706=5,7  .11764707=5,7  .11764705=5,5 .1176471=5,7 72=5,7  .1176470=5,5 .117647[3|5]=5,7  //.117648=5,7  //.117647=5,5 //.117649=5,7  //117645=5,5 //1176[3/4]=5,5 1165=5,7// 1176=5,5 //.1178/6=5,7 // 1175=5,5 //118=5,7 //117=5,5 //         //24.113/114/115=5,5//24.11=,5   //24.12=5,7 //24.16,14=5,7 //24.18=5.7//24.20=5,7 //24.1=5,5 //24.0=5,5  24.3 5,7 //24.25=5,7 // 24.2=5,7 //24.1=7,5  //25 5,7 //23.9=5,5 //24=5.5 //23.8=5.5 //23.3=err 5 //23            // 25  // 20    needs to be 22.5 or 7.5
// above might need to be fractional?


// 5Mhz / 10 = 500Khz    every 10 cpu cycles
// 5Mhz /4   = 1.25Mhz   every  4 cpu cycles
//
#define VIACLK_TO_CPUCLK(X) (via_clock_diff==2 ? ((X)*(XTIMER)(LISA2ECLKFACTOR)) :((X)*(XTIMER)(LISA1ECLKFACTOR)))
#define CPUCLK_TO_VIACLK(X) (via_clock_diff==2 ? ((X)/(XTIMER)(LISA2ECLKFACTOR)) :((X)/(XTIMER)(LISA1ECLKFACTOR)))


// How many microseconds should lisaem sleep between emulation cycles.  This allows us to slow down the emulator
// so that we can either get an acurate 5MHz clock, or be nice to the host OS.  This is implemented using poll with
// a null handle as per poll's man page.  The value of microsleep_tix is global so that it may be adjusted elsewhere
// in the code on the fly, as needed, perhaps it can be raised during I/O and idle mouse times.
#ifdef DEBUG
GLOBAL(int,microsleep_tix,0);
#else
GLOBAL(int,microsleep_tix,0);
#endif

// Scotty: Captain, we din' can reference it!
// Kirk:   Analysis, Mr. Spock?
// Spock:  Captain, it doesn't appear in the symbol table.
// Kirk:   Then it's of external origin?
// Spock:  Affirmative.
// Kirk:   Mr. Sulu, go to pass two.
// Sulu:   Aye aye, sir, going to pass two.



/*
 * But wait, there is mad to my method and reason!  Read on gentle hacker.  Here's the explanation.
 *
 * For sooth, thou shalt learneth...
 *
 * You see, C depends on variable and prototype declarations to know whether they be externed, to know the proper number and
 * types of parameters and return type of said functions.  If it does not know the proper types, it will warn, however, if the
 * prototype for a given function is incorrect, you can expect a maladjusted stack, and bad things will certainly happen.
 *
 * Having header files solves this - except it introduces another snag.  Should your header file delcare parameters differently
 * (aka incorrectly) than your .c file, you can expect warnings neither from gcc, nor from ld, which cannot know that this has
 * occured.
 *
 * One way to test for this is to include your header file into your C file, *BUT* this will not work from extern'ed functions.
 * gcc will complain about "conflicting types for...." and "previous declaration..." indicating a bug.  But you cannot use this
 * to self check your headers... so what to do? what to do?
 *
 * Another way is to use a program that automatically builds header files, but, meh - why would you want to have all your fn's
 * in a header file?
 *
 * Well, if you like Macro's, (and what good C programmer doesn't?) then the answer is clear.  Define a Macro to resolve as
 * extern when it should, and null when it shouldn't.  Easy as pie.
 *
 * I ran across this issue when I added several parameters to a function that I forgot was used externally in other code.
 * The program compiled just fine, and crashed beautifully.  gdb was able to solve the issue, but I thought I'd kill it for
 * good.  Always, always, always, program defensively.
 *
 *
 *
 */

#ifdef EXTERNX
#undef EXTERNX
#endif
#ifndef IN_FLIFLO_QUEUE_C
 #define EXTERNX extern
#else
 #define EXTERNX ;
#endif
EXTERNX int fliflo_buff_is_full(FLIFLO_QUEUE_t *b);
EXTERNX int fliflo_buff_has_data(FLIFLO_QUEUE_t *b);
EXTERNX int fliflo_buff_is_empty(FLIFLO_QUEUE_t *b);
EXTERNX uint32 fliflo_buff_size(FLIFLO_QUEUE_t *b);
EXTERNX uint32 fliflo_buff_percent_full(FLIFLO_QUEUE_t *b);
EXTERNX int fliflo_buff_add(FLIFLO_QUEUE_t *b,uint8 data);
EXTERNX uint8 fliflo_buff_pop(FLIFLO_QUEUE_t *b);
EXTERNX uint8 fliflo_buff_get(FLIFLO_QUEUE_t *b);
EXTERNX uint8 fliflo_buff_peek(FLIFLO_QUEUE_t *b);
EXTERNX uint8 fliflo_buff_peek_end(FLIFLO_QUEUE_t *b);
EXTERNX int fliflo_buff_create(FLIFLO_QUEUE_t *b, uint32 size);
EXTERNX void fliflo_buff_destroy(FLIFLO_QUEUE_t *b);

//extern void alertlog(char *alert);

//#endif

#define UI_LOG( level, fmt, args... ) {fprintf(buglog,"%s:%s:%d: ",__FILE__,__FUNCTION__,__LINE__); fprintf(buglog,  fmt , ## args); fprintf(buglog,"\n");fflush(buglog);}

DECLARE(char,_msg_alert[1024]);
DECLARE(char,_msg_alert2[1024]);


#ifdef DEBUG

   extern void dumpmmu(uint8 c, FILE *out);
   extern void dumpmmupage(uint8 c, uint8 i, FILE *out);




  /*define check_iib() {my_check_iib(__FILE__,__FUNCTION__,__LINE__);}
     ifndef IN_CPU68K_C
     extern void my_check_iib(char *filename, char *function, long line);
     endif
  */
   #define check_iib() {;}


// do full iib sanity check
//#define DEBUG_LOG( level, fmt, args... ) { if ( level <= DEBUGLEVEL ) {fprintf(buglog,"%s:%s:%d: ",__FILE__,__FUNCTION__,__LINE__); fprintf(buglog,  fmt , ## args); fprintf(buglog,"\n"); fflush(buglog);if (do_iib_check) my_check_iib(__FILE__,__FUNCTION__,__LINE__);} }
// don't do iib sanity check - speed things up

   #define DEBUG_LOG( level, fmt, args... ) { if ( (level <= DEBUGLEVEL) && debug_log_enabled)                        \
   {fprintf(buglog,"%s:%s:%d:",__FILE__,__FUNCTION__,__LINE__); fprintf(buglog,  fmt , ## args);                      \
    fprintf(buglog,"\n"); fflush(buglog); fflush(stdout);}                                                            }

   // this is needed because gdb doesn't tell you where your program quit from, just gives you the octal version of the exit
   // parameter which is chopped to 9 bits for some oddball reason.
   #define EXIT(x) {fprintf(stderr,"%s:%s:%d: exit with code :%d",__FILE__,__FUNCTION__,__LINE__,x);\
                    fprintf(buglog,"%s:%s:%d: exit with code :%d",__FILE__,__FUNCTION__,__LINE__,x);\
                    fflush(stderr); fflush(buglog); exit(x);}

/*
     if (mmu_trans!=mmu_trans_all[context] || mmu!=mmu_all[context] || (start && context))
        { fprintf(buglog,"\n\n\nBUGCHK: context:%d start:%d seg1/2:%d/%d\n",context,start,segment1,segment2);
          fprintf(buglog,"BUGCHK: mmu_trans=%p [0]=%p [1]=%p [2]=%p [3]=%p [4]=%p\n", mmu_trans,mmu_trans_all[0],mmu_trans_all[1],mmu_trans_all[2],mmu_trans_all[3],mmu_trans_all[4]);
          fprintf(buglog,"BUGCHK: mmu=%p mmu_all[0]=%p [1]=%p [2]=%p [3]=%p [4]=%p\n\n\n",mmu,mmu_all[0],mmu_all[1],mmu_all[2],mmu_all[3],mmu_all[4]);
          _EXIT(1); }
     }

fprintf(buglog,"context:%d videoram @ %08x\n",context,videolatchaddress); fflush(buglog);
*/
#else
  #define DEBUG_LOG( level, fmt, args... )  {}
  #define check_iib() {}
  #define EXIT(x)  {exit(x);}



#endif

   #define ALERT_LOG( level, fmt, args... ) { if ( (level <= DEBUGLEVEL) )                                            \
   {                                                                                                                  \
    fprintf(stderr,"%s:%s:%d:",__FILE__,__FUNCTION__,__LINE__); fprintf(stderr,  fmt , ## args);                      \
    fprintf(stderr,"\n"); fflush(stderr);                                                                             \
   }                                        }


///////// Memory access macros//////////////////////////////////////////////////////////////////////////////////////////////////




/******* Memory/MMU related defines, protos and vars *******/


// Context Selectors
#define CXASEL   (1+( segment1|segment2)                 )
#define CXSEL    (1+((segment1|segment2)&(lastsflag?0:3)))
#define CXSASEL ((1+((segment1|segment2)&(lastsflag?0:3))) & (start?0:7) )


// mmu cache coherency
#define SET_MMU_DIRTY(x)  {mmudirty=(x); mmudirty_all[CXASEL]=mmudirty;}
#define GET_MMU_DIRTY(x)  {mmudirty=     mmudirty_all[CXASEL];}
#define GET_MMUS_DIRTY(x) {mmudirty=     mmudirty_all[CXSASEL];}

// are we trying to access a changed MMU block?  If so rebuild it!
#define CHECK_DIRTY_MMU(addr)  {if (context && (mmu[((addr) & 0x00fe0000)>>17].changed)) {SET_MMU_DIRTY(0xdec0de); mmuflush(0);}}

// filter out segment # - i.e. keep page+offset
#define   MMUXXFILT 0x0001ffff

//#define SEGCHOP 1  /// bad - causes POST to get stuck

#ifdef SEGCHOP
#define MMU_X_FIL 0x0001ffff
#else
#define MMU_X_FIL 0x00ffffff
#endif

#define MMUSEGFILT 0x00fe0000
#define MMUEPAGEFL 0x00fffe00
//#define TWOMEGMLIM 0x001fffff

GLOBAL(uint32,TWOMEGMLIM,0x001fffff);








#ifndef IN_REG68K_C  /////////////////////////////////////////////////////////////////////////////////////////////////////////
// __CYGWIN__ wrapper added by Ray Arachelian for LisaEm to prevent crashes in reg68k_ext exec
#ifdef __CYGWIN__
 uint32 reg68k_pc;
 uint32 *reg68k_regs;
 t_sr reg68k_sr;
#else
//#if (!(defined(PROCESSOR_ARM) || defined(PROCESSOR_SPARC) || defined(PROCESSOR_INTEL) ))
#if (!(defined(PROCESSOR_ARM) || defined(PROCESSOR_SPARC)  ))      //20051125
uint32 reg68k_pc;
uint32 *reg68k_regs;
t_sr reg68k_sr;
#endif
#endif

#else


#ifdef __CYGWIN__
 extern uint32 reg68k_pc;
 extern uint32 *reg68k_regs;
 extern t_sr reg68k_sr;
#else
#if (!(defined(PROCESSOR_ARM) || defined(PROCESSOR_SPARC) || defined(PROCESSOR_INTEL) ))
 extern uint32 reg68k_pc;
 extern uint32 *reg68k_regs;
 extern t_sr reg68k_sr;
#endif
#endif


#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



DECLARE(viatype,via[9]);
GLOBAL(uint8,via_running,0); // If any VIA has a runing timer/SHIFTREG, then this is set (using bitmap of vianumber)

extern uint32 pc24;
// Used for Exception processing in Address/BUS errors
extern uint16 InstructionRegister;
extern uint8  CPU_function_code;
extern uint8  CPU_READ_MODE;


extern void contrastchange(void);

extern uint8 get_next_timer_id(void);

extern void cops_reset(void);
extern void disable_vidram(void);
extern void enable_vidram(void);
extern uint8 via1_ira(uint8 regnum);
extern void via1_ora(uint8 data,uint8 regnum);
extern void print_pc_and_regs(char *text);

extern uint8 viaX_ira(viatype *V,uint8 regnum);
extern uint8 viaX_irb(viatype *V);
extern void  viaX_ora(viatype *V, uint8 data, uint8 regnum);
extern void  viaX_orb(viatype *V, uint8 data);

extern void reset_via(int i);

extern void set_crdy_line(void);
extern void clr_crdy_line(void);
extern int  is_crdy_line(void);
extern void set_kb_data_ready(void) ;
extern int is_vector_available(int avno);
extern void lisa_external_nmi_vector(uint32 addr);
extern void reg68k_internal_autovector(int avno);
extern int get_address_mmu_rfn_type(uint32 addr);
extern void reg68k_sanity_check_bitorder(void);

extern char *mspace(lisa_mem_t fn);
extern int  floppy_insert(char *Image);
extern void apple_1(void);
extern void apple_2(void);
extern void apple_3(void);
extern void apple_dot(void);
extern void apple_dot_down(void);
extern void apple_dot_up(void);
extern void send_nmi_key(void);
extern void presspowerswitch(void);


extern void shift_option_0(void);
extern void shift_option_4(void);
extern void shift_option_7(void);

extern void add_mouse_event(int16 x, int16 y, int8 button);

extern void mmuflush(uint16 opts);
extern lisa_mem_t rmmuslr2fn(uint16 slr, uint32 a9);
extern t_ipc_table *get_ipct(void);
extern void checkcontext(uint8 c, char *text);
extern void cpu68k_printipc(t_ipc * ipc);
#ifdef DEBUG
  extern void dump_scc(void);
#endif
extern char *printslr(char *x, long size, uint16 slr);
extern lisa_mem_t rmmuslr2fn(uint16 slr, uint32 a9);
extern void get_slr_page_range(int cx,int seg, int16 *pagestart, int16 *pageend, lisa_mem_t *rfn, lisa_mem_t *wfn);
extern lisa_mem_t rmmuslr2fn(uint16 slr, uint32 a9);



extern void dumpram(char *reason);
extern void    dumpvia(void);
extern void fdumpvia1(FILE *out);
extern void fdumpvia2(FILE *out);
extern void fliflo_dump(FLIFLO_QUEUE_t *b,char *s);


#ifdef DEBUG
extern char *slrname(uint16 slr);
#endif

#ifdef DEBUG
extern void validate_mmu_segments(char *from);
#endif



#ifdef EXTERNX
#undef EXTERNX
#endif
#ifndef IN_ROM_C
 #define EXTERNX extern
#else
 #define EXTERNX ;
#endif
EXTERNX int has_xl_screenmod(void);
EXTERNX int16 read_dtc_rom(  char *filename, uint8 *ROM);
EXTERNX int16 read_split_rom(char *filename, uint8 *ROMMX);
EXTERNX int16 read_rom(      char *filename, uint8 *ROMMX);
EXTERNX uint8 *decode_lisa_icon(uint8 *icon);
EXTERNX int read_parallel_card_rom(char *filename);




// not likely that these are needed, but could be useful elsewhere:
EXTERNX uint8 ishex(char c);
EXTERNX uint8 gethex(char c);
EXTERNX uint8 brol(uint8 outdata, uint8 loop);
EXTERNX uint16 wrol(uint16 outdata, uint8 loop);
EXTERNX uint16 lrol(uint32 outdata, uint8 loop);



#ifdef EXTERNX
#undef EXTERNX
#endif
#ifndef IN_MMU_C
 #define EXTERNX extern
#else
 #define EXTERNX ;
#endif
EXTERNX void init_lisa_mmu(void);
EXTERNX void checkcontext(uint8 c, char *text);

#ifdef EXTERNX
#undef EXTERNX
#endif
#ifndef IN_UI_LOG_C
 #define EXTERNX extern
#else
 #define EXTERNX ;
#endif
EXTERNX void ui_err(const char *text, ...);
EXTERNX void ui_error(const char *text, ...);
EXTERNX void ui_log(unsigned int loglevel, const char *text, ...);
EXTERNX void ui_log_verbose(const char *text, ...);
EXTERNX void ui_log_request(const char *text, ...);
EXTERNX void ui_log_critical(const char *text, ...);
EXTERNX void ui_log_debug3(const char *text, ...);
EXTERNX void ui_log_debug2(const char *text, ...);
EXTERNX void ui_log_debug1(const char *text, ...);
EXTERNX void ui_log_user(const char *text, ...);
EXTERNX void ui_log_normal(const char *text, ...);


#ifdef EXTERNX
#undef EXTERNX
#endif
#ifndef  IN_VIA6522_C
 #define EXTERNX extern
#else
 #define EXTERNX ;
#endif
EXTERNX void all_vias_run(void);
EXTERNX void init_vias(void);
EXTERNX void get_next_timer_event(void);
EXTERNX void check_current_timer_irq(void);
EXTERNX uint8 next_timer_id(void);
EXTERNX void VIAProfileLoop(int vianum, ProFileType *P, int event);






#ifndef IN_IRQ_C
extern int8 IRQRingBufferAdd(uint8 irql, uint32 address);
extern uint8 IRQRingGet(void);
extern void init_IRQ(void);
#endif







#ifndef IN_COPS_C
extern void cops_keyboard_id(void);
extern void set_keyboard_id(int32);
#endif

#ifndef IN_FLOPPY_C
extern void floppy_go6504(void);
#endif

#ifndef IN_PROFILE_C
extern void ProfileLoop(ProFileType *P, int event);
extern void ProfileReset(ProFileType *P);
extern void ProfileResetOff(ProFileType *P);
#endif

#define PROLOOP_EV_IRB 0                   // event=0 <- Read from IRB
#define PROLOOP_EV_IRA 1                   // event=1 <- Read from IRA
#define PROLOOP_EV_ORA 2                   // event=2 <- write to ORA
#define PROLOOP_EV_ORB 3                   // event=3 <- write to ORB
#define PROLOOP_EV_NUL 4                   // event=4 <- null event - called occasionally by event handling to allow timeouts



/****** Video ***********/

GLOBAL(uint8,bitdepth,0);

GLOBAL(uint8,softmemerror,0);
GLOBAL(uint8,harderror,0);
GLOBAL(uint8,videoirq,0);
GLOBAL(uint8,bustimeout,0);
GLOBAL(uint8,videobit,0);
GLOBAL(uint8,serialnumshiftcount,0);
GLOBAL(uint8,serialnumshift,0);
DECLARE(uint8,serialnum[8]);
DECLARE(uint8,serialnum240[32]);

#define MAXSOUNDS 10

GLOBAL(int,SoundLastOne,5);
DECLARE(char,*SoundBuffer[MAXSOUNDS]);
DECLARE(uint32,SoundBufSize[MAXSOUNDS]);

GLOBAL(int,z8530_last_irq_status_bits,0);
DECLARE(char,*scc_a_port);  DECLARE(char,scc_a_OPTIONS[1024]);
DECLARE(char,*scc_b_port);  DECLARE(char,scc_b_OPTIONS[1024]);
DECLARE(int,scc_a_telnet_port);
DECLARE(int,scc_b_telnet_port);


GLOBAL(int,scc_a_IW,0);
GLOBAL(int,scc_b_IW,1);

GLOBAL(uint8,serial_a,SCC_NOTHING);
GLOBAL(uint8,serial_b,SCC_NOTHING);

GLOBAL(FILE,*scc_a_port_F,NULL);
GLOBAL(FILE,*scc_b_port_F,NULL);

// USed by memory diag tests
GLOBAL(uint8,*mem_parity_bits1,NULL);
GLOBAL(uint8,*mem_parity_bits2,NULL);
GLOBAL(uint32,last_bad_parity_adr,0);

GLOBAL(int,scc_running,0);



extern void sound_fork(void);
extern void sound_play(uint16 freq);
extern void sound_off(void);

//DECLARE(scc_func_t, scc_fn[2] );

//  5 sets of mmu registers, each of 128 segments.
//  (4 are real lisa mmu contexts, added an extra for easier START mode translation)
DECLARE(mmu_t,mmu_all[5][128]);

// *mmu is in current context. i.e. mmu = mmu_all[4] sets context[4] (START mode).  I do this so that I

// don't have to dereference the array every single memory access as that would add an unnecessary expense.
// i.e. mmu_all[SEGMENT1+SEGMENT2|SETUP][(address>>17)&0x7f] is very expensive, but
// mmu[(address>>17)&0x7f] is far less expensive.
GLOBAL(mmu_t,*mmu,NULL);

DECLARE(mmu_trans_t,mmu_trans_all[5][32768]);

/* sadly if I used enums for lisa_mem_t.readfn/.writefn gcc would allocate 4 bytes for each so the total
   or this would be 12 bytes x 32768 pages/context x 5 = 1.85MB of ram for this table.  Instead I used
   defines and uint8's for lisa_mem_t, so this should be 1.25M depending on how they're packed    */

GLOBAL(mmu_trans_t,*mmu_trans,mmu_trans_all[0]); // ptr to current context, so I don't have to do expensive double array deref.
// i.e. mmu_trans=mmu_trans_all[0] is context 0.

// Refs for Generator's mem68k.c
// These are initialized by init_lisa_mmu.

// temp vars to play with, don't include these in vars.c
DECLARE(mmu_t,m); // temp variable to play with
DECLARE(mmu_trans_t,mt); // mmu translation - temporary var
DECLARE(mmu_trans_t,*lastvideo_mt);

// result of mmu logical->physical translation
GLOBAL(int32,physaddr,0);

// Lisa I/O Space types and other types of accesses.

// These used to be enums, but enums in gcc are 32 bits long, and unless you want to pass
// the -fshort-enums which may break other things, I'd rather just set them up as #DEFINEs and
// be done with it.  Could have left them as enums, but that would bloat the mmu structures I use
// as mmu_trans_all would grow huge.  consts can't be used to set arrays, so #DEFINES they'll have
// to be.


// Note, these are the letters Ox not zero x, so they're perfectly legal symbol names
// It makes for easier reading of addresses when reading the source. :)

// Regular (non-special) I/O address space.  Subject to MMU mapping.

#define OxERROR           0     /* This should never be used - it indicates a bug in our code */
#define OxUnused	 	  1     /* unused I/O space address (only used in I/O space map) */
#define Ox0000_slot1l	  2
#define Ox2000_slot1h	  3
#define Ox4000_slot2l	  4
#define Ox6000_slot2h	  5
#define Ox8000_slot3l	  6
#define Oxa000_slot3h	  7
#define Oxc000_flopmem	  8
#define Oxd000_ff_space   9
#define Oxd200_sccz8530	 10
#define Oxd800_par_via2	 11
#define Oxdc00_cops_via1 12
#define Oxe000_latches	 13
#define Oxe800_videlatch 14
#define Oxf000_memerror  15
#define Oxf800_statreg	 16

// Real Lisa memory
#define ram		         17     /* Plain old RAM, or stack access.                                   */
#define vidram           18     /* same as ram, but flag on write that screen needs refreshing       */
#define ro_violn         19     /* Read only violation - what trap should I call? See schematic      */
#define bad_page         20     /* Bad page or unallocated segment - what trap here?                 */

// Special I/O space
#define sio_rom          21     /* access to ROM via sio mode                                        */
#define sio_mrg          22     /* mmu register being accessed.  Which depends on bit 3 of addr      */

#define sio_mmu          23     /* access ram or other spaces via the mmu (bit14=1 in address)       */


// Disparcher to I/O space (dispatcher to the Ox????_ fn's list above)
#define io               24     /* This is a dispatcher for I/O space when we don't know the address */

#define Oxd400_amd9512   25

#define OxVoid           26     /* Reserved mem fn's that do nothing, and return junk                */

#define MAX_LISA_MFN     27     /* The last Lisa Memory function type we have                        */



// I/O Address Maps.  These are used to initialize the fn pointers on the OUTPUT side of the mmu.
GLOBAL(char,*memspaces[],
{
	"00-OxERROR",
	"01-OxUnused",
	"02-Ox0000_slot1l",
	"03-Ox2000_slot1h",
	"04-Ox4000_slot2l",
	"05-Ox6000_slot2h",
	"06-Ox8000_slot3l",
	"07-Oxa000_slot3h",
	"08-Oxc000_flopmem",
    "09-0xd000_ff_space",
	"10-Oxd200_sccz8530",
	"11-Oxd800_par_via2",
	"12-Oxdc00_cops_via1",
	"13-Oxe000_latches",
	"14-Oxe800_videlatch",
	"15-Oxf000_memerror",
	"16-Oxf800_statreg",
	"17-ram",
	"18-vidram",
	"19-ro_violn",
	"20-bad_page",
	"21-sio_rom",
	"22-sio_mrg",
	"23-sio_mmu",
    "24-io",
    "25-Oxd400_amd9512",
    "26-OxVoid"
});


ACGLOBAL(lisa_mem_t,io_map[],
{                  // +0             // +1              // +2              //+3
/*                 +000              +200                +400              +600 */
/* 0xfc0000 : */   Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,     //   0
/* 0xfc0800 : */   Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,     //   4
/* 0xfc1000 : */   Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,     //   8
/* 0xfc1800 : */   Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,    Ox0000_slot1l,     //  12
/* 0xfc2000 : */   Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,     //  16

/* 0xfc2800 : */   Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,     //  20
/* 0xfc3000 : */   Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,     //  24
/* 0xfc3800 : */   Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,    Ox2000_slot1h,     //  28
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfc4000 : */   Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,     //  32
/* 0xfc4800 : */   Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,     //  36

/* 0xfc5000 : */   Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,     //  40
/* 0xfc5800 : */   Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,    Ox4000_slot2l,     //  44
/* 0xfc6000 : */   Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,     //  48
/* 0xfc6800 : */   Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,     //  52
/* 0xfc7000 : */   Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,     //  56

/* 0xfc7800 : */   Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,    Ox6000_slot2h,     //  60
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfc8000 : */   Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,     //  74
/* 0xfc8800 : */   Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,     //  78
/* 0xfc9000 : */   Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,     //  82
/* 0xfc9800 : */   Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,    Ox8000_slot3l,     //  86

/* 0xfca000 : */   Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,     //  90
/* 0xfca800 : */   Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,     //  94
/* 0xfcb000 : */   Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,     //  98
/* 0xfcb800 : */   Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,    Oxa000_slot3h,     // 102
///////////////////////////////////////////////////////////////////////////////////////////////////////

/* 0xfcc000 : */   Oxc000_flopmem,   Oxc000_flopmem,   Oxc000_flopmem,   Oxc000_flopmem,    // 106

/* 0xfcc800 : */   Oxc000_flopmem,   Oxc000_flopmem,   Oxc000_flopmem,   Oxc000_flopmem,    // 110

///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfcd000 : */   Oxd000_ff_space,  Oxd200_sccz8530,  Oxd400_amd9512,   Oxd400_amd9512,    // 114
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfcd800 : */   Oxd800_par_via2,  Oxd800_par_via2,  Oxdc00_cops_via1, Oxdc00_cops_via1,  // 118
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfce000 : */   Oxe000_latches,   OxUnused,         OxUnused,         OxUnused,          // 122
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfce800 : */   Oxe800_videlatch, Oxe800_videlatch, Oxe800_videlatch, Oxe800_videlatch,  // 126
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfcf000 : */   Oxf000_memerror,  Oxf000_memerror,  Oxf000_memerror,  Oxf000_memerror,   // 130
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* 0xfcf800 : */   Oxf800_statreg,   Oxf800_statreg,   Oxf800_statreg,   Oxf800_statreg     // 134
/*                 +000              +200                +400              +600 */
});



ACGLOBAL(lisa_mem_t,sio_map[], // danger! this is for use on pre-MMU addresses - lop off the top 17 bits of the address
                      // as well as the low 9 bits ( address & 01fe00)
{
/*               000       200       400       600       800       a00        c00       e00 */
/*000000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, // 8/line
/*001000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom,
/*002000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom,
/*003000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom,
/*004000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*005000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*006000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*007000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*008000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*009000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*00a000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*00b000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*00c000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*00d000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*00e000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*00f000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*010000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom,
/*011000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom,
/*012000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom,
/*013000:*/ sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom, sio_rom,
/*014000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*015000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*016000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*017000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*018000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*019000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*01a000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*01b000:*/ sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg, sio_mrg,
/*01c000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*01d000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*01e000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu,
/*01f000:*/ sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu, sio_mmu
});


GLOBAL(int,dispmemready,0);

// Status register in memory.c
//------------------------------------------------------------------------------
#define STATREG_SOFTMEM_ERR 1           /* lisa doesn't use this bit */
#define STATREG_HARDMEM_ERR 2           /* Parity error bit 1=not set, 0=set */
#define STATREG_VERTICALRTC 4
#define STATREG_BUSTIMEOUT  8
#define STATREG_VIDEOBIT   16
#define STATREG_CSYNC      32
#define STATREG_HORIZONTAL 32
#define STATREG_INVBIT     64           /* lisa doesn't use this bit normally */
#define STATREG_UNUSEDBIT 128           /* lisa doesn't use this bit */






#ifndef IN_CPU68K_C
extern void free_ipct(t_ipc_table *ipct);
#endif

extern int diss68k_gettext(t_ipc * ipc, char *text);

// memory function definitions.
uint8 *(*mem68k_memptr[MAX_LISA_MFN]) (uint32 addr);
uint8 (*mem68k_fetch_byte[MAX_LISA_MFN]) (uint32 addr);
uint16 (*mem68k_fetch_word[MAX_LISA_MFN]) (uint32 addr);
uint32 (*mem68k_fetch_long[MAX_LISA_MFN]) (uint32 addr);
void (*mem68k_store_byte[MAX_LISA_MFN]) (uint32 addr, uint8 data);
void (*mem68k_store_word[MAX_LISA_MFN]) (uint32 addr, uint16 data);
void (*mem68k_store_long[MAX_LISA_MFN]) (uint32 addr, uint32 data);

extern int get_exs2_pending_irq_empty(void);
extern int get_exs1_pending_irq_empty(void);
extern int get_exs0_pending_irq_empty(void);

extern int get_exs0_pending_irq_2xpar(void);
extern int get_exs1_pending_irq_2xpar(void);
extern int get_exs2_pending_irq_2xpar(void);

GLOBAL(int,(*get_exs0_pending_irq)(void),&get_exs0_pending_irq_empty);
GLOBAL(int,(*get_exs1_pending_irq)(void),&get_exs1_pending_irq_empty);
GLOBAL(int,(*get_exs2_pending_irq)(void),&get_exs2_pending_irq_empty);


/* These macro "functions" are used by generator.  I use the above macro's in here just to avoid
   macro soup insanity.  Yeah, so they're probably not super duper optimized, but there's time
   for that once the emulator is debugged and working. -- RA */
//define fetchaddr(addr) mem68k_memptr[RFN_MMU_TRANS](addr)
//define fetchbyte(addr) mem68k_fetch_byte[RFN_MMU_TRANS](addr)
//define fetchword(addr) mem68k_fetch_word[RFN_MMU_TRANS](addr)
//define fetchlong(addr) mem68k_fetch_long[RFN_MMU_TRANS](addr)
//define storebyte(addr,data) mem68k_store_byte[WFN_MMU_TRANS ](addr,data)
//define storeword(addr,data) mem68k_store_word[WFN_MMU_TRANS ](addr,data)
//define storelong(addr,data) mem68k_store_long[WFN_MMU_TRANS ](addr,data)

extern void   lisa_ram_safe_setbyte(uint8 context, uint32 address,uint8 data);
extern uint8  lisa_ram_safe_getbyte(uint8 context, uint32 address);
extern uint16 lisa_ram_safe_getword(uint8 context, uint32 address);
extern uint32 lisa_ram_safe_getlong(uint8 context, uint32 address);

#ifndef INMEMORYDOTC
  extern void  *dmem68k_memptr(    char *file, char *function, int line,uint32 a);
  extern uint8  dmem68k_fetch_byte(char *file, char *function, int line,uint32 a );
  extern uint16 dmem68k_fetch_word(char *file, char *function, int line,uint32 a );
  extern uint32 dmem68k_fetch_long(char *file, char *function, int line,uint32 a );
  extern void   dmem68k_store_byte(char *file, char *function, int line,uint32 a, uint8  d);
  extern void   dmem68k_store_word(char *file, char *function, int line,uint32 a, uint16 d);
  extern void   dmem68k_store_long(char *file, char *function, int line,uint32 a, uint32 d);
#endif


#ifdef DEBUGMEMCALLS

  #define fetchaddr(a)   dmem68k_memptr(    (char *)__FILE__,(char *)__FUNCTION__,__LINE__,a)
  #define fetchbyte(a)   dmem68k_fetch_byte((char *)__FILE__,(char *)__FUNCTION__,__LINE__,(uint32)(a))
  #define fetchword(a)   dmem68k_fetch_word((char *)__FILE__,(char *)__FUNCTION__,__LINE__,(uint32)(a))
  #define fetchlong(a)   dmem68k_fetch_long((char *)__FILE__,(char *)__FUNCTION__,__LINE__,(uint32)(a))
  #define storebyte(a,d) dmem68k_store_byte((char *)__FILE__,(char *)__FUNCTION__,__LINE__,(uint32)(a),( uint8)(d))
  #define storeword(a,d) dmem68k_store_word((char *)__FILE__,(char *)__FUNCTION__,__LINE__,(uint32)(a),(uint16)(d))
  #define storelong(a,d) dmem68k_store_long((char *)__FILE__,(char *)__FUNCTION__,__LINE__,(uint32)(a),(uint32)(d))
#else

  #define fetchaddr(a)   mem68k_memptr[    (mmu_trans[((a) & 0x00fffe00)>>9].readfn)](a)
  #define fetchbyte(a)   mem68k_fetch_byte[(mmu_trans[((a) & 0x00fffe00)>>9].readfn)](a)
  #define fetchword(a)   mem68k_fetch_word[(mmu_trans[((a) & 0x00fffe00)>>9].readfn)](a)
  #define fetchlong(a)   mem68k_fetch_long[(mmu_trans[((a) & 0x00fffe00)>>9].readfn)](a)
  #define storebyte(a,d) mem68k_store_byte[(mmu_trans[((a) & 0x00fffe00)>>9].writefn)]((a),( uint8)(d))
  #define storeword(a,d) mem68k_store_word[(mmu_trans[((a) & 0x00fffe00)>>9].writefn)]((a),(uint16)(d))
  #define storelong(a,d) mem68k_store_long[(mmu_trans[((a) & 0x00fffe00)>>9].writefn)]((a),(uint32)(d))
#endif




// As these are defined in memory.c, we cannot define them here as externs.  like duh!
#ifndef INMEMORYDOTC
// fn protos
extern uint8  *lisa_mptr_OxERROR(uint32 addr);
extern uint8  lisa_rb_OxERROR(uint32 addr);
extern uint16 lisa_rw_OxERROR(uint32 addr);
extern uint32 lisa_rl_OxERROR(uint32 addr);
extern void   lisa_wb_OxERROR(uint32 addr, uint8 data);
extern void   lisa_ww_OxERROR(uint32 addr, uint16 data);
extern void   lisa_wl_OxERROR(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_OxUnused(uint32 addr);
extern uint8  lisa_rb_OxUnused(uint32 addr);
extern uint16 lisa_rw_OxUnused(uint32 addr);
extern uint32 lisa_rl_OxUnused(uint32 addr);
extern void   lisa_wb_OxUnused(uint32 addr, uint8 data);
extern void   lisa_ww_OxUnused(uint32 addr, uint16 data);
extern void   lisa_wl_OxUnused(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Ox0000_slot1l(uint32 addr);
extern uint8  lisa_rb_Ox0000_slot1l(uint32 addr);
extern uint16 lisa_rw_Ox0000_slot1l(uint32 addr);
extern uint32 lisa_rl_Ox0000_slot1l(uint32 addr);
extern void   lisa_wb_Ox0000_slot1l(uint32 addr, uint8 data);
extern void   lisa_ww_Ox0000_slot1l(uint32 addr, uint16 data);
extern void   lisa_wl_Ox0000_slot1l(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Ox2000_slot1h(uint32 addr);
extern uint8  lisa_rb_Ox2000_slot1h(uint32 addr);
extern uint16 lisa_rw_Ox2000_slot1h(uint32 addr);
extern uint32 lisa_rl_Ox2000_slot1h(uint32 addr);
extern void   lisa_wb_Ox2000_slot1h(uint32 addr, uint8 data);
extern void   lisa_ww_Ox2000_slot1h(uint32 addr, uint16 data);
extern void   lisa_wl_Ox2000_slot1h(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Ox4000_slot2l(uint32 addr);
extern uint8  lisa_rb_Ox4000_slot2l(uint32 addr);
extern uint16 lisa_rw_Ox4000_slot2l(uint32 addr);
extern uint32 lisa_rl_Ox4000_slot2l(uint32 addr);
extern void   lisa_wb_Ox4000_slot2l(uint32 addr, uint8 data);
extern void   lisa_ww_Ox4000_slot2l(uint32 addr, uint16 data);
extern void   lisa_wl_Ox4000_slot2l(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Ox6000_slot2h(uint32 addr);
extern uint8  lisa_rb_Ox6000_slot2h(uint32 addr);
extern uint16 lisa_rw_Ox6000_slot2h(uint32 addr);
extern uint32 lisa_rl_Ox6000_slot2h(uint32 addr);
extern void   lisa_wb_Ox6000_slot2h(uint32 addr, uint8 data);
extern void   lisa_ww_Ox6000_slot2h(uint32 addr, uint16 data);
extern void   lisa_wl_Ox6000_slot2h(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Ox8000_slot3l(uint32 addr);
extern uint8  lisa_rb_Ox8000_slot3l(uint32 addr);
extern uint16 lisa_rw_Ox8000_slot3l(uint32 addr);
extern uint32 lisa_rl_Ox8000_slot3l(uint32 addr);
extern void   lisa_wb_Ox8000_slot3l(uint32 addr, uint8 data);
extern void   lisa_ww_Ox8000_slot3l(uint32 addr, uint16 data);
extern void   lisa_wl_Ox8000_slot3l(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxa000_slot3h(uint32 addr);
extern uint8  lisa_rb_Oxa000_slot3h(uint32 addr);
extern uint16 lisa_rw_Oxa000_slot3h(uint32 addr);
extern uint32 lisa_rl_Oxa000_slot3h(uint32 addr);
extern void   lisa_wb_Oxa000_slot3h(uint32 addr, uint8 data);
extern void   lisa_ww_Oxa000_slot3h(uint32 addr, uint16 data);
extern void   lisa_wl_Oxa000_slot3h(uint32 addr, uint32 data);


extern uint8 lisa_rb_ext_2par_via(viatype *V,uint32 addr);
extern void  lisa_wb_ext_2par_via(viatype *V,uint32 addr, uint8 xvalue);

extern uint8  *lisa_mptr_2x_parallel_l(uint32 addr);
extern uint8  lisa_rb_2x_parallel_l(uint32 addr);
extern uint16 lisa_rw_2x_parallel_l(uint32 addr);
extern uint32 lisa_rl_2x_parallel_l(uint32 addr);
extern void   lisa_wb_2x_parallel_l(uint32 addr, uint8 data);
extern void   lisa_ww_2x_parallel_l(uint32 addr, uint16 data);
extern void   lisa_wl_2x_parallel_l(uint32 addr, uint32 data);


extern uint8  *lisa_mptr_2x_parallel_h(uint32 addr);
extern uint8  lisa_rb_2x_parallel_h(uint32 addr);
extern uint16 lisa_rw_2x_parallel_h(uint32 addr);
extern uint32 lisa_rl_2x_parallel_h(uint32 addr);
extern void   lisa_wb_2x_parallel_h(uint32 addr, uint8 data);
extern void   lisa_ww_2x_parallel_h(uint32 addr, uint16 data);
extern void   lisa_wl_2x_parallel_h(uint32 addr, uint32 data);


extern uint8  *lisa_mptr_Oxc000_flopmem(uint32 addr);
extern uint8  lisa_rb_Oxc000_flopmem(uint32 addr);
extern uint16 lisa_rw_Oxc000_flopmem(uint32 addr);
extern uint32 lisa_rl_Oxc000_flopmem(uint32 addr);
extern void   lisa_wb_Oxc000_flopmem(uint32 addr, uint8 data);
extern void   lisa_ww_Oxc000_flopmem(uint32 addr, uint16 data);
extern void   lisa_wl_Oxc000_flopmem(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxd200_sccz8530(uint32 addr);
extern uint8  lisa_rb_Oxd200_sccz8530(uint32 addr);
extern uint16 lisa_rw_Oxd200_sccz8530(uint32 addr);
extern uint32 lisa_rl_Oxd200_sccz8530(uint32 addr);
extern void   lisa_wb_Oxd200_sccz8530(uint32 addr, uint8 data);
extern void   lisa_ww_Oxd200_sccz8530(uint32 addr, uint16 data);
extern void   lisa_wl_Oxd200_sccz8530(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxd800_par_via2(uint32 addr);
extern uint8  lisa_rb_Oxd800_par_via2(uint32 addr);
extern uint16 lisa_rw_Oxd800_par_via2(uint32 addr);
extern uint32 lisa_rl_Oxd800_par_via2(uint32 addr);
extern void   lisa_wb_Oxd800_par_via2(uint32 addr, uint8 data);
extern void   lisa_ww_Oxd800_par_via2(uint32 addr, uint16 data);
extern void   lisa_wl_Oxd800_par_via2(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxdc00_cops_via1(uint32 addr);
extern uint8  lisa_rb_Oxdc00_cops_via1(uint32 addr);
extern uint16 lisa_rw_Oxdc00_cops_via1(uint32 addr);
extern uint32 lisa_rl_Oxdc00_cops_via1(uint32 addr);
extern void   lisa_wb_Oxdc00_cops_via1(uint32 addr, uint8 data);
extern void   lisa_ww_Oxdc00_cops_via1(uint32 addr, uint16 data);
extern void   lisa_wl_Oxdc00_cops_via1(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxe000_latches(uint32 addr);
extern uint8  lisa_rb_Oxe000_latches(uint32 addr);

extern uint16 lisa_rw_Oxe000_latches(uint32 addr);
extern uint32 lisa_rl_Oxe000_latches(uint32 addr);
extern void   lisa_wb_Oxe000_latches(uint32 addr, uint8 data);
extern void   lisa_ww_Oxe000_latches(uint32 addr, uint16 data);
extern void   lisa_wl_Oxe000_latches(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxe800_videlatch(uint32 addr);
extern uint8  lisa_rb_Oxe800_videlatch(uint32 addr);
extern uint16 lisa_rw_Oxe800_videlatch(uint32 addr);
extern uint32 lisa_rl_Oxe800_videlatch(uint32 addr);
extern void   lisa_wb_Oxe800_videlatch(uint32 addr, uint8 data);
extern void   lisa_ww_Oxe800_videlatch(uint32 addr, uint16 data);
extern void   lisa_wl_Oxe800_videlatch(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxf000_memerror(uint32 addr);
extern uint8  lisa_rb_Oxf000_memerror(uint32 addr);
extern uint16 lisa_rw_Oxf000_memerror(uint32 addr);
extern uint32 lisa_rl_Oxf000_memerror(uint32 addr);
extern void   lisa_wb_Oxf000_memerror(uint32 addr, uint8 data);
extern void   lisa_ww_Oxf000_memerror(uint32 addr, uint16 data);
extern void   lisa_wl_Oxf000_memerror(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxf800_statreg(uint32 addr);
extern uint8  lisa_rb_Oxf800_statreg(uint32 addr);
extern uint16 lisa_rw_Oxf800_statreg(uint32 addr);
extern uint32 lisa_rl_Oxf800_statreg(uint32 addr);
extern void   lisa_wb_Oxf800_statreg(uint32 addr, uint8 data);
extern void   lisa_ww_Oxf800_statreg(uint32 addr, uint16 data);
extern void   lisa_wl_Oxf800_statreg(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_ram(uint32 addr);
extern uint8  lisa_rb_ram(uint32 addr);
extern uint16 lisa_rw_ram(uint32 addr);
extern uint32 lisa_rl_ram(uint32 addr);
extern void   lisa_wb_ram(uint32 addr, uint8 data);
extern void   lisa_ww_ram(uint32 addr, uint16 data);
extern void   lisa_wl_ram(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_ro_violn(uint32 addr);
extern uint8  lisa_rb_ro_violn(uint32 addr);
extern uint16 lisa_rw_ro_violn(uint32 addr);
extern uint32 lisa_rl_ro_violn(uint32 addr);
extern void   lisa_wb_ro_violn(uint32 addr, uint8 data);
extern void   lisa_ww_ro_violn(uint32 addr, uint16 data);
extern void   lisa_wl_ro_violn(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_bad_page(uint32 addr);
extern uint8  lisa_rb_bad_page(uint32 addr);
extern uint16 lisa_rw_bad_page(uint32 addr);
extern uint32 lisa_rl_bad_page(uint32 addr);
extern void   lisa_wb_bad_page(uint32 addr, uint8 data);
extern void   lisa_ww_bad_page(uint32 addr, uint16 data);
extern void   lisa_wl_bad_page(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_sio_rom(uint32 addr);
extern uint8  lisa_rb_sio_rom(uint32 addr);
extern uint16 lisa_rw_sio_rom(uint32 addr);
extern uint32 lisa_rl_sio_rom(uint32 addr);
extern void   lisa_wb_sio_rom(uint32 addr, uint8 data);
extern void   lisa_ww_sio_rom(uint32 addr, uint16 data);
extern void   lisa_wl_sio_rom(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_sio_mrg(uint32 addr);
extern uint8  lisa_rb_sio_mrg(uint32 addr);
extern uint16 lisa_rw_sio_mrg(uint32 addr);
extern uint32 lisa_rl_sio_mrg(uint32 addr);
extern void   lisa_wb_sio_mrg(uint32 addr, uint8 data);
extern void   lisa_ww_sio_mrg(uint32 addr, uint16 data);
extern void   lisa_wl_sio_mrg(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_sio_mmu(uint32 addr);
extern uint8  lisa_rb_sio_mmu(uint32 addr);
extern uint16 lisa_rw_sio_mmu(uint32 addr);
extern uint32 lisa_rl_sio_mmu(uint32 addr);
extern void   lisa_wb_sio_mmu(uint32 addr, uint8 data);
extern void   lisa_ww_sio_mmu(uint32 addr, uint16 data);
extern void   lisa_wl_sio_mmu(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_vidram(uint32 addr);
extern uint8  lisa_rb_vidram(uint32 addr);
extern uint16 lisa_rw_vidram(uint32 addr);
extern uint32 lisa_rl_vidram(uint32 addr);
extern void   lisa_wb_vidram(uint32 addr, uint8 data);
extern void   lisa_ww_vidram(uint32 addr, uint16 data);
extern void   lisa_wl_vidram(uint32 addr, uint32 data);

extern void   lisa_wb_xlvidram_parity(uint32 addr, uint8  data);
extern void   lisa_ww_xlvidram_parity(uint32 addr, uint16 data);
extern void   lisa_wl_xlvidram_parity(uint32 addr, uint32 data);
extern void   lisa_wb_xlvidram(uint32 addr, uint8  data);
extern void   lisa_ww_xlvidram(uint32 addr, uint16 data);
extern void   lisa_wl_xlvidram(uint32 addr, uint32 data);



extern uint8  *lisa_mptr_io(uint32 addr);
extern uint8  lisa_rb_io(uint32 addr);
extern uint16 lisa_rw_io(uint32 addr);
extern uint32 lisa_rl_io(uint32 addr);
extern void   lisa_wb_io(uint32 addr, uint8 data);
extern void   lisa_ww_io(uint32 addr, uint16 data);
extern void   lisa_wl_io(uint32 addr, uint32 data);

extern uint8  lisa_rb_ram_parity(uint32 addr);
extern uint16 lisa_rw_ram_parity(uint32 addr);
extern uint32 lisa_rl_ram_parity(uint32 addr);
extern void   lisa_wb_ram_parity(uint32 addr, uint8  data);
extern void   lisa_ww_ram_parity(uint32 addr, uint16 data);
extern void   lisa_wl_ram_parity(uint32 addr, uint32 data);

extern uint8  lisa_rb_vidram_parity(uint32 addr);
extern uint16 lisa_rw_vidram_parity(uint32 addr);
extern uint32 lisa_rl_vidram_parity(uint32 addr);
extern void   lisa_wb_vidram_parity(uint32 addr, uint8  data);
extern void   lisa_ww_vidram_parity(uint32 addr, uint16 data);
extern void   lisa_wl_vidram_parity(uint32 addr, uint32 data);

extern uint8  *lisa_mptr_Oxd000_ff_space(uint32 addr);
extern uint8   lisa_rb_Oxd000_ff_space(uint32 addr);
extern uint16  lisa_rw_Oxd000_ff_space(uint32 addr);
extern uint32  lisa_rl_Oxd000_ff_space(uint32 addr);
extern void    lisa_wb_Oxd000_ff_space(uint32 addr, uint8  data);
extern void    lisa_ww_Oxd000_ff_space(uint32 addr, uint16 data);
extern void    lisa_wl_Oxd000_ff_space(uint32 addr, uint32 data);


// not implemented - for future AMD9512 FPU's
extern uint8  *lisa_mptr_Oxd400_amd9512(uint32 addr);
extern uint8   lisa_rb_Oxd400_amd9512(uint32 addr);
extern uint16  lisa_rw_Oxd400_amd9512(uint32 addr);
extern uint32  lisa_rl_Oxd400_amd9512(uint32 addr);
extern void    lisa_wb_Oxd400_amd9512(uint32 addr, uint8  data);
extern void    lisa_ww_Oxd400_amd9512(uint32 addr, uint16 data);
extern void    lisa_wl_Oxd400_amd9512(uint32 addr, uint32 data);

// reserved memory access for mmu pages out of scope that should not cause mmu_exception
extern uint8  *lisa_mptr_OxVoid(uint32 addr);
extern uint8   lisa_rb_OxVoid(uint32 addr);
extern uint16  lisa_rw_OxVoid(uint32 addr);
extern uint32  lisa_rl_OxVoid(uint32 addr);
extern void    lisa_wb_OxVoid(uint32 addr, uint8  data);
extern void    lisa_ww_OxVoid(uint32 addr, uint16 data);
extern void    lisa_wl_OxVoid(uint32 addr, uint32 data);


#endif


extern void keystroke_cops(unsigned char c);
extern void send_cops_keycode(int k);

extern void apple_1(void);
extern void apple_2(void);
extern void apple_3(void);
extern void apple_enternum(void);
extern void apple_S(void);              // for lisatest
extern void apple_enter(void);
extern void apple_renter(void);

extern void vidfixromchk(uint8 *s);
extern void keystroke_cops(unsigned char c);
extern void init_IRQ(void);
extern void init_Profiles(void);

extern void profile_unmount(void);

extern void init_sounds(void);
extern void initialize_scc(void);
extern void init_telnet_serial_port(int portnum);
extern uint16 crc16(uint16 crc, uint8 data);
extern void seek_mouse_event(void);
extern void init_floppy(long iorom);


extern void lisa_addrerror(uint32 addr);
extern void lisa_busrerror(uint32 addr);
extern void lisa_mmu_exception(uint32 addr);
extern void lisa_nmi_vector(uint32 addr);


extern CPP2C void lisa_powered_off(void);
extern CPP2C void lisa_rebooted(void);
extern CPP2C void messagebox(char *s, char *t);
extern CPP2C int yesnomessagebox(char *s, char *t);
extern CPP2C void floppy_motor_sounds(int track);
extern CPP2C void eject_floppy_animation(void);
extern CPP2C void save_pram(void);
extern CPP2C int pickprofilesize(char *filename);

extern CPP2C char *getDocumentsDir(void);
extern CPP2C char *getResourcesDir(void);
//extern CPP2C char *getExecutablePath(void);

extern CPP2C int ImageWriter_LisaEm_Init(int iwnum);
extern CPP2C void iw_formfeed(int iw);
extern CPP2C void ImageWriterLoop(int iw,uint8 c);
extern CPP2C void gen_clock_diff_sleep(long diff);





void set_loram_clk(void);

extern void lisa_diag2_on_mem(void);
extern void lisa_diag2_off_mem(void);

extern void  lisa_buserror(uint32 addr);
extern void  mc68k_reset(void);
extern uint8 lisa_rb_Oxd200_sccz8530(uint32 addr);
extern uint8 lisa_rb_Oxd800_par_via2(uint32 addr);
extern void  lisa_wb_Oxd800_par_via2(uint32 addr, uint8 data);
extern uint8 lisa_rb_Oxdc00_cops_via1(uint32 addr);
extern void  lisa_wb_Oxdc00_cops_via1(uint32 addr, uint8 data);
extern void  fixromchk(void);
extern int   checkromchksum(void);

extern void my_dump_cops(FILE *buglog);
//extern char *dis_movem(char *out, uint16, opcode, uint16 msk);


extern void get_next_timer_event(void);
extern void FloppyIRQ_time_up(void);

extern void debug_on(char *reason);
extern void debug_off(void);
extern char *chk_mtmmu(uint32 a, uint8 write);
extern void print_via_profile_state(char *s, uint8 data, viatype *V);
extern int profile_mount(char *filename, ProFileType *P);
extern void reg68k_external_autovector(int avno);

extern CPP2C void LisaScreenRefresh(void);


extern uint8 is_lisa_mouse_on(void);
extern void cops_timer_alarm(void);
extern void flag_vert_retrace_irq(void);

extern int get_nmi_pending_irq(void);
extern int get_scc_pending_irq(void);
//extern int get_exs0_pending_irq(void);
//extern int get_exs1_pending_irq(void);
//extern int get_exs2_pending_irq(void);
//extern int get_cops_pending_irq(void);  made static inline and placed in reg68k.c for speedup
extern int get_irq1_pending_irq(void);
extern void reset_video_timing(void);

#ifdef DEBUG
extern char *get_rom_label(uint32 pc24);
extern char *getvector(int v);
#endif

extern uint32 getreg(uint8 regnum);

extern void printlisatime(FILE *out);
extern void normalize_lisa_clock(void);
extern void normalize_lisa_set_clock(void);

extern void ascii_screendump(void);
uint8 cmp_screen_hash(uint8 *hashtable1, uint8 *hashtable2);



#define GETSEG(a)   (((a & MMUSEGFILT)>>17) & 0x7f)
#define GETEPAGE(a) (((a & MMUEPAGEFL)>>9)  & 0x7fff)

/* these are a bit too conservative perhaps, but they will prevent address overflows.              0x00fe0000*/
//** DANGER ** REMOVE & TWOMEGLIM!!! ***
#define CHK_MMU_REGST(addr)     (        (((       mmu[(addr & MMUSEGFILT)>>17].sor<<9) +  (addr & MMUXXFILT))              ))
//#define RAM_MMU_REGST(addr)     (lisaram+(((       mmu[(addr & MMUSEGFILT)>>17].sor<<9) +  (addr & MMUXXFILT))  & TWOMEGMLIM))
#define CHK_MMU_A_REGST(c,addr) (        (((mmu_all[c][(addr & MMUSEGFILT)>>17].sor<<9) +  (addr & MMUXXFILT))              ))
#define RAM_MMU_A_REGST(c,addr) (lisaram+(((mmu_all[c][(addr & MMUSEGFILT)>>17].sor<<9) +  (addr & MMUXXFILT))              ))

#define VALIDATE_MMU(addr)       (        (((       mmu[(addr & MMUSEGFILT)>>17].sor<<9) + (addr & MMUXXFILT))  & TWOMEGMLIM))

// cheato
//#define XCHK_MMU_TRANS(addr)     (        (((       mmu[(addr & MMUSEGFILT)>>17].sor<<9) + (addr & MMUXXFILT))  & TWOMEGMLIM))
//#define XRAM_MMU_TRANS(addr)     (lisaram+(((       mmu[(addr & MMUSEGFILT)>>17].sor<<9) + (addr & MMUXXFILT))  & TWOMEGMLIM))
//#define XCHK_MMU_A_TRANS(c,addr) (        (((mmu_all[c][(addr & MMUSEGFILT)>>17].sor<<9) + (addr & MMUXXFILT))  & TWOMEGMLIM))
//#define XRAM_MMU_A_TRANS(c,addr) (lisaram+(((mmu_all[c][(addr & MMUSEGFILT)>>17].sor<<9) + (addr & MMUXXFILT))  & TWOMEGMLIM))


// half way cheato
//#define XXCHK_MMU_TRANS(addr)     ((        (((addr & 0xffffff)+mmu_trans[       (addr & MMUEPAGEFL)>>9].sor9) + (addr & MMUXXFILT)  & TWOMEGMLIM)))
//#define XXRAM_MMU_TRANS(addr)     ((lisaram+(((addr & 0xffffff)+mmu_trans[       (addr & MMUEPAGEFL)>>9].sor9) + (addr & MMUXXFILT)  & TWOMEGMLIM)))
//#define XXCHK_MMU_A_TRANS(c,addr) ((        (((addr & 0xffffff)+mmu_trans_all[c][(addr & MMUEPAGEFL)>>9].sor9) + (addr & MMUXXFILT)  & TWOMEGMLIM)))
//#define XXRAM_MMU_A_TRANS(c,addr) ((lisaram+(((addr & 0xffffff)+mmu_trans_all[c][(addr & MMUEPAGEFL)>>9].sor9) + (addr & MMUXXFILT)  & TWOMEGMLIM)))

// needs to be above fn def below
GLOBAL(uint32,maxlisaram,2*1024*1024);
GLOBAL(uint32,minlisaram,0);


#define RAM512K  ( 512*1024)
#define RAM1024K (1024*1024)
#define RAM1536K (1536*1024)
#define RAM2048K (2048*1024)

#ifdef BULLSHYTE_ALLOW_1536K_RAM
   inline static uint32 RAMWARP(uint32 a, uint32 b, int c)
   {


    #ifdef OFFOFFOFFF20051205DEBUG
    uint32 sgn, usgn, xadd1, xadd2, slrchk;

    sgn=  ((int32)( (int32)(b & 0x00ffffff)+(int32)(mmu_trans_all[c][(b & MMUEPAGEFL)>>9].address))    & 0x1fffff);
    usgn= ((uint32)(        (b & 0x00ffffff)+       (mmu_trans_all[c][(b & MMUEPAGEFL)>>9].address)))  & 0x1FFFFF;
    xadd1=CHK_MMU_A_REGST(c,b);
    xadd2= 0x1FFFFF & (((mmu_all[c][b>>17].sor<<9) + (b & 0x1fe00))|(b &511));
    slrchk=0x1FFFFF & (((mmu_all[c][b>>17].slr & 0xff)<<9) + (b & 0x1fe00));

    if (sgn!=usgn)   ALERT_LOG(0,"DANGER - Signed MMU addition not the same as unsigned %d/%08x!=%08x(unsigned)",c,sgn,usgn);
    if (xadd1!=usgn) ALERT_LOG(0,"DANGER - Unsigned MMU addition not the same as CHK_MMU_A_REGST%d/%08x!=%08x(unsigned)",c,xadd1,usgn);
    if (xadd2!=usgn) ALERT_LOG(0,"DANGER - Unsigned MMU addition not the same HWG83 p 36 pdf %d/%08x!=%08x(unsigned)",c,xadd2,usgn);
    if (slrchk>0x1FFFFF) DEBUG_LOG(0,"SLR>1FFFFF");

    //if (maxlisaram==RAM2048K) return a;                                    // fast exit


    DEBUG_LOG(0," Current context=%d, context passed to me:%d slrchk:%08x >1FFFFF:%d",context,c,slrchk, (slrchk>0x1FFFFF));
    DEBUG_LOG(0," a=%08x inputaddr:%08x 2mblim s/b 001fffff:%08x mmu-delta:%d signed addition:%08x, normal addition:%08x via mmureg:%08x seg:%d sor:%04x slr:%04x",
    a,b,TWOMEGMLIM ,
    mmu_trans_all[c][(b & MMUEPAGEFL)>>9].address,
    ( (int32)(b & 0x00ffffff)+(int32)(mmu_trans_all[c][(b & MMUEPAGEFL)>>9].address)),
    (        (b & 0x00ffffff)+       (mmu_trans_all[c][(b & MMUEPAGEFL)>>9].address)),

    CHK_MMU_A_REGST(c,b),
    ((b & MMUSEGFILT)>>17 ),
    mmu_all[c][(b & MMUSEGFILT)>>17].sor,
    mmu_all[c][(b & MMUSEGFILT)>>17].slr
                                               );
    #endif

    #ifdef BULLSHYTE
    switch (maxlisaram)
    {
        case (RAM512K ):   // single 1/2MB board
                         if (a<RAM512K ) return a;                         // inside 512K
                         //20051109 if (a<RAM1024K) return (a & (RAM512K-1)); // warp
                         memset(&lisaram[maxlisaram],0xff,128);
                         return maxlisaram;                   // above 1MB is junk - return highest and hope for best

        case (RAM1024K):   // two 1/2 MB boards //
                        if (a<=RAM1024K) return a;
                        else return maxlisaram;
                        //20060106
                        // if (a<RAM512K)    {
                        //                       DEBUG_LOG(0,"<512KB");
                        //                       memset(&lisaram[maxlisaram],0xff,16); return maxlisaram;} //20051109
                        // if (a>=RAM1536K)  {
                        //                       DEBUG_LOG(0,">1536KB");
                        //                       memset(&lisaram[maxlisaram],0xff,16); return maxlisaram;} //20051109
                        //
                        // return a-RAM512K;                                                // 1st board 1MB
                         //20051109 return a-RAM1024K;                                    // 2nd warp

        case (RAM1536K):  // one 1MB board and one 1/2mb board
                         if (a<RAM1536K) return a;                                       // first board 1.5M
                         {memset(&lisaram[maxlisaram],0xff,128); return maxlisaram;}                  // 2nd board junk


        default:          return (a & 0x00ffffff);
    }
    #endif
   return a;
   }
                                                            //12345678
 #define RAM_MMU_TRANS(addr)     ((lisaram+RAMWARP((((addr) & 0x00ffffff) +mmu_trans[       (addr & MMUEPAGEFL)>>9].address),addr,context))               )
 #define RAM_MMU_A_TRANS(c,addr) ((lisaram+RAMWARP((((addr) & 0x00ffffff) +mmu_trans_all[c][(addr & MMUEPAGEFL)>>9].address),addr,c ))               )
 #define CHK_MMU_TRANS(addr)     ((        RAMWARP((((addr) & 0x00ffffff) +mmu_trans[       (addr & MMUEPAGEFL)>>9].address),addr,context)) & (TWOMEGMLIM))
 #define CHK_MMU_A_TRANS(c,addr) ((        RAMWARP((((addr) & 0x00ffffff) +mmu_trans_all[c][(addr & MMUEPAGEFL)>>9].address),addr,c )) & (TWOMEGMLIM))

#else

  // these first two are very dangerous! - need to deprecate their use!
                                                            //12345678
  #define RAM_MMU_TRANS(addr)            (lisaram+(((addr & 0x00ffffff) +mmu_trans[       (addr & MMUEPAGEFL)>>9].address)  ))
  #define RAM_MMU_A_TRANS(c,addr)        (lisaram+(((addr & 0x00ffffff) +mmu_trans_all[c][(addr & MMUEPAGEFL)>>9].address)  ))
  #define CHK_MMU_TRANS(addr)            (        (((addr & 0x00ffffff) +mmu_trans[       (addr & MMUEPAGEFL)>>9].address)  ))
  #define CHK_MMU_A_TRANS(c,addr)        (        (((addr & 0x00ffffff) +mmu_trans_all[c][(addr & MMUEPAGEFL)>>9].address)  ))

#endif


#define RFN_MMU_TRANS(addr)     (mmu_trans[                                    (addr & MMUEPAGEFL)>>9].readfn )
#define WFN_MMU_TRANS(addr)     (mmu_trans[                                    (addr & MMUEPAGEFL)>>9].writefn)
#define RFN_MMU_A_TRANS(c,addr) (mmu_trans_all[c][                             (addr & MMUEPAGEFL)>>9].readfn )
#define WFN_MMU_A_TRANS(c,addr) (mmu_trans_all[c][                             (addr & MMUEPAGEFL)>>9].writefn)


// Memory checking macros
// CHK- check only - no bus error
// RCHK-Read check - call bus error
// WCHK-Write check - call bus error
// QCHK_RAM_LIMITS - check and quit emulator

// can call CHK_RAM_LIMITS, then check for -1, else do lisaram[physaddr] for a pointer
#define CHK_RAM_LIMITS(addr)                                                                                                 \
{       physaddr=(        (((addr & 0x00ffffff)+mmu_trans[       (addr & MMUEPAGEFL)>>9].address) ));                        \
        if (physaddr<(signed)minlisaram) physaddr=-2;  else if (physaddr>(signed)maxlisaram) physaddr=-1;                    \
}

#define CHK_RAM_A_LIMITS(c,addr)                                                                                             \
{       physaddr=(        (((addr & 0x00ffffff)+mmu_trans_all[c][(addr & MMUEPAGEFL)>>9].address) ));                        \
        if (physaddr<(signed)minlisaram) physaddr=-2;  else if (physaddr>(signed)maxlisaram) physaddr=-1;                    \
}


// check, and quit if error
#define QCHK_RAM_LIMITS(addr)                                                                                                \
{       physaddr=(        (((addr & 0x00ffffff)+mmu_trans[       (addr & MMUEPAGEFL)>>9].address) ));                        \
        if (physaddr<0||physaddr>(signed)maxlisaram)                                                                         \
           {fprintf(buglog,"*** %s:%s:%d:: mem out of range! @ %d/%08x :: @mmu=%08x\n\n",                                    \
                           __FILE__,__FUNCTION__,__LINE__,context,addr,physaddr); EXIT(2); }                                 \
}

// check and abort on read, or write
// if (TWOMEGMLIM==0x001fffff && (physaddr<minlisaram||((uint32)(physaddr))>maxlisaram))
//
// if ((physaddr<minlisaram||((uint32)(physaddr))>maxlisaram))

#define RCHK_RAM_LIMITS(addr)                                                                                                \
{          physaddr=(        ((addr+mmu_trans[       (addr & MMUEPAGEFL)>>9].address) ));                                    \
           if (physaddr<minlisaram) return 0x75;  else if (physaddr>(signed)maxlisaram) physaddr=-1;                         \
           if ((((uint32)(physaddr))>=maxlisaram))                                                                           \
           {fprintf(buglog,"*** %s:%s:%d:: mem out of range! @ %d/%08x :: @mmu=%08x\n\n",                                    \
            __FILE__,__FUNCTION__,__LINE__,context,addr,physaddr); CPU_READ_MODE=1; lisa_mmu_exception(addr); return 0x93;}  \
}                                                                     //lisa_mmu_exception(addr);


#define WCHK_RAM_LIMITS(addr)                                                                                                \
{          physaddr=(        ((addr+mmu_trans[       (addr & MMUEPAGEFL)>>9].address) ));                                    \
           if (physaddr<minlisaram) return;       else if (physaddr>(signed)maxlisaram) physaddr=-1;                         \
           if ((((uint32)(physaddr))>=maxlisaram))                                                                           \
           {fprintf(buglog,"*** %s:%s:%d:: mem out of range! @ %d/%08x :: @mmu=%08x\n\n",                                    \
           __FILE__,__FUNCTION__,__LINE__,context,addr,physaddr);  CPU_READ_MODE=0; lisa_mmu_exception(addr); return;}       \
}                                                                     //lisa_mmu_exception(addr);


#define XRCHK_RAM_LIMITS(addr) {}
#define XWCHK_RAM_LIMITS(addr) {}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#endif
