/*********************************************************
 * WARNING: file is automatically generated do not modify
 *
 * File:	custom.c (generated by fab_custom.c)
 *
 * Abstract:	This code that simulates the dragonball's
 *		intelligent peripheral modules and system
 *		interface logic.
 *
 * WARNING: file is automatically generated do not modify
 *********************************************************/

#include <ctype.h>
#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>

#if 0
#include "config.h"
#endif
#include "sysdeps.h"
#include "shared.h"
#include "memory.h"
#include "custom.h"
#include "newcpu.h"

extern int sram_protect;

/* dragonball register locations */

#define SCR	0xf000
#define GRPBASEA	0xf100
#define GRPBASEC	0xf104
#define GRPMASKA	0xf108
#define GRPMASKC	0xf10c
#define CSA0	0xf110
#define CSA1	0xf114
#define CSA2	0xf118
#define CSA3	0xf11c
#define CSC0	0xf130
#define CSC1	0xf134
#define CSC2	0xf138
#define CSC3	0xf13c
#define PLLCR	0xf200
#define PLLFSR	0xf202
#define PCTLR	0xf207
#define IVR	0xf300
#define ICR	0xf302
#define IMR	0xf304
#define IWR	0xf308
#define ISR	0xf30c
#define IPR	0xf310
#define PCDIR	0xf410
#define PCDATA	0xf411
#define PCSEL	0xf413
#define PDDIR	0xf418
#define PDDATA	0xf419
#define PDPUEN	0xf41a
#define PDPOL	0xf41c
#define PDIRQEN	0xf41d
#define PDIRQEDGE	0xf41f
#define PEDIR	0xf420
#define PEDATA	0xf421
#define PEPUEN	0xf422
#define PESEL	0xf423
#define PFDIR	0xf428
#define PFDATA	0xf429
#define PFPUEN	0xf42a
#define PFSEL	0xf42b
#define PGDIR	0xf430
#define PGDATA	0xf431
#define PGPUEN	0xf432
#define PGSEL	0xf433
#define PJDIR	0xf438
#define PJDATA	0xf439
#define PJSEL	0xf43b
#define PKDIR	0xf440
#define PKDATA	0xf441
#define PKPUEN	0xf442
#define PKSEL	0xf443
#define PMDIR	0xf448
#define PMDATA	0xf449
#define PMPUEN	0xf44a
#define PMSEL	0xf44b
#define PWMC	0xf500
#define PWMP	0xf502
#define PWMW	0xf504
#define TCTL1	0xf600
#define TPRER1	0xf602
#define TCMP1	0xf604
#define TCN1	0xf608
#define TSTAT1	0xf60a
#define TCTL2	0xf60c
#define TPRER2	0xf60e
#define TCMP2	0xf610
#define TCN2	0xf614
#define TSTAT2	0xf616
#define WCSR	0xf618
#define WCN	0xf61c
#define SPIMDATA	0xf800
#define SPIMCONT	0xf802
#define USTCNT	0xf900
#define UBAUD	0xf902
#define URX	0xf904
#define UTX	0xf906
#define UMISC	0xf908
#define LSSA	0xfa00
#define LVPW	0xfa05
#define LXMAX	0xfa08
#define LYMAX	0xfa0a
#define LCXP	0xfa18
#define LCYP	0xfa1a
#define LCWCH	0xfa1c
#define LBLKC	0xfa1f
#define LPICF	0xfa20
#define LPOLCF	0xfa21
#define LPXCD	0xfa25
#define LCKCON	0xfa27
#define LLBAR	0xfa29
#define LOTCR	0xfa2b
#define LPOSR	0xfa2d
#define LFRCM	0xfa31
#define LGPMR	0xfa32
#define RTCHMS	0xfb00
#define RTCALARM	0xfb04
#define RTCCTL	0xfb0c
#define RTCISR	0xfb0e
#define RTCIENR	0xfb10

/*
 * Hmmm... We need to differentiate the debugger using the
 * UART from other programs (PPP, etc.) using it.  We check
 * the global variable dbgInDebugger (at address 0x110) to
 * see if we're in the debugger.
 *
 * - Ian
 */
#define IN_DEBUGGER (get_byte(0x110))
#define DEBUGGER_WRITING (CustShptr->gdb_writefd >= 0 && IN_DEBUGGER)
#define DEBUGGER_READING (CustShptr->gdb_writefd >= 0 && IN_DEBUGGER)

/* dragonball register definitions */

static union {
	UBYTE x;
	struct {
		unsigned WDTH8	:1;
		unsigned RSVD	:1;
		unsigned DMAP	:1;
		unsigned SO	:1;
		unsigned BETEN	:1;
		unsigned PRV	:1;
		unsigned WPV	:1;
		unsigned BETO	:1;
	} anon;
} db_SCR;

static union {
	UWORD x;
	struct {
		unsigned V	:1;
		unsigned 	:3;
		unsigned GMA	:12;
	} anon;
} db_GRPBASEA, db_GRPBASEC;

static union {
	UWORD x;
	struct {
		unsigned 	:4;
		unsigned GMA	:12;
	} anon;
} db_GRPMASKA, db_GRPMASKC;

static union {
	ULONG x;
	struct {
		unsigned WAIT	:3;
		unsigned RO	:1;
		unsigned 	:4;
		unsigned AM	:8;
		unsigned BSW	:1;
		unsigned 	:7;
		unsigned AC	:8;
	} anon;
} db_CSA0, db_CSA1, db_CSA2, db_CSA3, db_CSC0, db_CSC1, db_CSC2, db_CSC3;

static union {
	UWORD x;
	struct {
		unsigned 	:3;
		unsigned DISPLL	:1;
		unsigned CLKEN	:1;
		unsigned 	:3;
		unsigned SYSCLKSEL	:3;
		unsigned PIXCLKSEL	:3;
		unsigned 	:2;
	} anon;
} db_PLLCR;

static union {
	UWORD x;
	struct {
		unsigned PC	:8;
		unsigned QC	:4;
		unsigned 	:2;
		unsigned PROT	:1;
		unsigned CLK32	:1;
	} anon;
} db_PLLFSR;

static union {
	UBYTE x;
	struct {
		unsigned WIDTH	:5;
		unsigned 	:1;
		unsigned STOP	:1;
		unsigned PCEN	:1;
	} anon;
} db_PCTLR;

static union {
	UBYTE x;
	struct {
		unsigned LEVEL	:3;
		unsigned VECTOR	:5;
	} anon;
} db_IVR;

static union {
	UWORD x;
	struct {
		unsigned 	:8;
		unsigned POL6	:1;
		unsigned POL3	:1;
		unsigned POL2	:1;
		unsigned POL1	:1;
		unsigned ET6	:1;
		unsigned ET3	:1;
		unsigned ET2	:1;
		unsigned ET1	:1;
	} anon;
} db_ICR;

static union {
	ULONG x;
	struct {
		unsigned SPIM	:1;
		unsigned TMR2	:1;
		unsigned UART	:1;
		unsigned WDT	:1;
		unsigned RTC	:1;
		unsigned LCDC	:1;
		unsigned KB	:1;
		unsigned PWM	:1;
		unsigned INT0	:1;
		unsigned INT1	:1;
		unsigned INT2	:1;
		unsigned INT3	:1;
		unsigned INT4	:1;
		unsigned INT5	:1;
		unsigned INT6	:1;
		unsigned INT7	:1;
		unsigned IRQ1	:1;
		unsigned IRQ2	:1;
		unsigned IRQ3	:1;
		unsigned IRQ6	:1;
		unsigned PEN	:1;
		unsigned SPIS	:1;
		unsigned TMR1	:1;
		unsigned IRQ7	:1;
		unsigned 	:8;
	} anon;
} db_IMR, db_IWR, db_ISR, db_IPR;

static union {
	UBYTE x;
	struct {
		unsigned MOCLK	:1;
		unsigned UDS	:1;
		unsigned LDS	:1;
		unsigned 	:1;
		unsigned NMI	:1;
		unsigned DTACK	:1;
		unsigned WE	:1;
		unsigned 	:1;
	} anon;
} db_PCDIR, db_PCDATA, db_PCSEL;

static union {
	UBYTE x;
	struct {
		unsigned BB0	:1;
		unsigned B1	:1;
		unsigned B2	:1;
		unsigned B3	:1;
		unsigned B4	:1;
		unsigned B5	:1;
		unsigned B6	:1;
		unsigned B7	:1;
	} anon;
} db_PDDIR, db_PDDATA, db_PDPUEN, db_PDPOL, db_PDIRQEN, db_PDIRQEDGE;

static union {
	UBYTE x;
	struct {
		unsigned A	:8;
	} anon;
} db_PEDIR, db_PEDATA, db_PEPUEN, db_PESEL, db_PFDIR, db_PFDATA, db_PFPUEN, db_PFSEL;

static union {
	UBYTE x;
	struct {
		unsigned UART_TXD	:1;
		unsigned UART_RXD	:1;
		unsigned PWMOUT	:1;
		unsigned TOUT2	:1;
		unsigned TIN2	:1;
		unsigned TOUT1	:1;
		unsigned TIN1	:1;
		unsigned RTCOUT	:1;
	} anon;
} db_PGDIR, db_PGDATA, db_PGPUEN, db_PGSEL;

static union {
	UBYTE x;
	struct {
		unsigned A	:8;
	} anon;
} db_PJDIR, db_PJDATA, db_PJSEL;

static union {
	UBYTE x;
	struct {
		unsigned SPIM_TXD	:1;
		unsigned SPIM_RXD	:1;
		unsigned SPIM_CLKO	:1;
		unsigned SPIS_EN	:1;
		unsigned SPIS_RXD	:1;
		unsigned SPIS_CLKI	:1;
		unsigned PCMCIA_CE2	:1;
		unsigned PCMCIA_CE1	:1;
	} anon;
} db_PKDIR, db_PKDATA, db_PKPUEN, db_PKSEL;

static union {
	UBYTE x;
	struct {
		unsigned CTS	:1;
		unsigned RTS	:1;
		unsigned IRQ6	:1;
		unsigned IRQ3	:1;
		unsigned IRQ2	:1;
		unsigned IRQ1	:1;
		unsigned PEN_IRQ	:1;
		unsigned UART_GPIO	:1;
	} anon;
} db_PMDIR, db_PMDATA, db_PMPUEN, db_PMSEL;

static union {
	UWORD x;
	struct {
		unsigned CLKSEL	:3;
		unsigned 	:1;
		unsigned PWMEN	:1;
		unsigned POL	:1;
		unsigned 	:1;
		unsigned PIN	:1;
		unsigned LOAD	:1;
		unsigned 	:5;
		unsigned IRQEN	:1;
		unsigned PWMIRQ	:1;
	} anon;
} db_PWMC;

static union {
	UWORD x;
	struct {
		unsigned PERIOD	:16;
	} anon;
} db_PWMP;

static union {
	UWORD x;
	struct {
		unsigned WIDTH	:16;
	} anon;
} db_PWMW;

static union {
	UWORD x;
	struct {
		unsigned TEN	:1;
		unsigned CLKSOURCE	:3;
		unsigned IRQEN	:1;
		unsigned OM	:1;
		unsigned CAPTURE_EDGE	:2;
		unsigned FRR	:1;
		unsigned 	:7;
	} anon;
} db_TCTL1;

static union {
	UWORD x;
	struct {
		unsigned PRESCALE	:8;
		unsigned 	:8;
	} anon;
} db_TPRER1;

static union {
	UWORD x;
	struct {
		unsigned COMPARE	:16;
	} anon;
} db_TCMP1;

static union {
	UWORD x;
	struct {
		unsigned COUNT	:16;
	} anon;
} db_TCN1;

static union {
	UWORD x;
	struct {
		unsigned COMP	:1;
		unsigned CAPT	:1;
		unsigned 	:14;
	} anon;
} db_TSTAT1;

static union {
	UWORD x;
	struct {
		unsigned TEN	:1;
		unsigned CLKSOURCE	:3;
		unsigned IRQEN	:1;
		unsigned OM	:1;
		unsigned CAPTURE_EDGE	:2;
		unsigned FRR	:1;
		unsigned 	:7;
	} anon;
} db_TCTL2;

static union {
	UWORD x;
	struct {
		unsigned PRESCALE	:8;
		unsigned 	:8;
	} anon;
} db_TPRER2;

static union {
	UWORD x;
	struct {
		unsigned COMPARE	:16;
	} anon;
} db_TCMP2;

static union {
	UWORD x;
	struct {
		unsigned COUNT	:16;
	} anon;
} db_TCN2;

static union {
	UWORD x;
	struct {
		unsigned COMP	:1;
		unsigned CAPT	:1;
		unsigned 	:14;
	} anon;
} db_TSTAT2;

static union {
	UWORD x;
	struct {
		unsigned WDEN	:1;
		unsigned FI	:1;
		unsigned LOCK	:1;
		unsigned WDRST	:1;
		unsigned 	:12;
	} anon;
} db_WCSR;

static union {
	UWORD x;
	struct {
		unsigned COUNT	:16;
	} anon;
} db_WCN;

static union {
	UWORD x;
	struct {
		unsigned DATA	:16;
	} anon;
} db_SPIMDATA;

static union {
	UWORD x;
	struct {
		unsigned BITCOUNT	:4;
		unsigned POL	:1;
		unsigned PHA	:1;
		unsigned IRQEN	:1;
		unsigned SPIMIRQ	:1;
		unsigned XCH	:1;
		unsigned SPMEN	:1;
		unsigned 	:3;
		unsigned DATARATE	:3;
	} anon;
} db_SPIMCONT;

static union {
	UWORD x;
	struct {
		unsigned TX_AVAIL_ENABLE	:1;
		unsigned TX_HALF_ENABLE	:1;
		unsigned TX_EMPTY_ENABLE	:1;
		unsigned RX_READY_ENABLE	:1;
		unsigned RX_HALF_ENABLE	:1;
		unsigned RX_FULL_ENABLE	:1;
		unsigned CTS_DELTA_ENABLE	:1;
		unsigned GPIO_DELTA_ENABLE	:1;
		unsigned BITS_8	:1;
		unsigned STOP_BITS	:1;
		unsigned ODD_EVEN	:1;
		unsigned PARITY_ENABLE	:1;
		unsigned RX_CLK_CONT	:1;
		unsigned TX_ENABLE	:1;
		unsigned RX_ENABLE	:1;
		unsigned UART_ENABLE	:1;
	} anon;
} db_USTCNT;

static union {
	UWORD x;
	struct {
		unsigned PRESCALER	:6;
		unsigned 	:2;
		unsigned DIVIDE	:3;
		unsigned BAUD_SRC	:1;
		unsigned GPIO_SRC	:1;
		unsigned GPIO_DIR	:1;
		unsigned GPIO	:1;
		unsigned GPIO_DELTA	:1;
	} anon;
} db_UBAUD;

static union {
	UWORD x;
	struct {
		unsigned DATA	:8;
		unsigned PARITY_ERROR	:1;
		unsigned BREAK	:1;
		unsigned FRAME_ERROR	:1;
		unsigned OVRUN	:1;
		unsigned 	:1;
		unsigned DATA_READY	:1;
		unsigned FIFO_HALF	:1;
		unsigned FIFO_FULL	:1;
	} anon;
} db_URX;

static union {
	UWORD x;
	struct {
		unsigned DATA	:8;
		unsigned CTS_DELTA	:1;
		unsigned CTS_STATUS	:1;
		unsigned 	:1;
		unsigned IGNORE_CTS	:1;
		unsigned SEND_BREAK	:1;
		unsigned TX_AVAIL	:1;
		unsigned FIFO_HALF	:1;
		unsigned FIFO_EMPTY	:1;
	} anon;
} db_UTX;

static union {
	UWORD x;
	struct {
		unsigned 	:2;
		unsigned TX_POL	:1;
		unsigned RX_POL	:1;
		unsigned IRDA_LOOP	:1;
		unsigned IRDA_ENABLE	:1;
		unsigned RTS	:1;
		unsigned RTS_CONT	:1;
		unsigned 	:4;
		unsigned LOOP	:1;
		unsigned FORCE_PERR	:1;
		unsigned CLK_SRC	:1;
		unsigned 	:1;
	} anon;
} db_UMISC;

static union {
	ULONG x;
	struct {
		unsigned SSA	:32;
	} anon;
} db_LSSA;

static union {
	UBYTE x;
	struct {
		unsigned VPW	:8;
	} anon;
} db_LVPW;

static union {
	UWORD x;
	struct {
		unsigned XMAX	:10;
		unsigned 	:6;
	} anon;
} db_LXMAX;

static union {
	UWORD x;
	struct {
		unsigned YMAX	:10;
		unsigned 	:6;
	} anon;
} db_LYMAX;

static union {
	UWORD x;
	struct {
		unsigned CXP	:10;
		unsigned 	:4;
		unsigned CC	:2;
	} anon;
} db_LCXP;

static union {
	UWORD x;
	struct {
		unsigned CYP	:10;
		unsigned 	:6;
	} anon;
} db_LCYP;

static union {
	UWORD x;
	struct {
		unsigned CH	:5;
		unsigned 	:3;
		unsigned CW	:5;
		unsigned 	:3;
	} anon;
} db_LCWCH;

static union {
	UBYTE x;
	struct {
		unsigned BD	:7;
		unsigned BKEN	:1;
	} anon;
} db_LBLKC;

static union {
	UBYTE x;
	struct {
		unsigned GS	:1;
		unsigned PBSIZ	:2;
		unsigned 	:5;
	} anon;
} db_LPICF;

static union {
	UBYTE x;
	struct {
		unsigned 	:8;
	} anon;
} db_LPOLCF;

static union {
	UBYTE x;
	struct {
		unsigned PCD	:6;
		unsigned 	:2;
	} anon;
} db_LPXCD;

static union {
	UBYTE x;
	struct {
		unsigned PCDS	:1;
		unsigned DWIDTH	:1;
		unsigned WS	:4;
		unsigned DMA16	:1;
		unsigned LCDCON	:1;
	} anon;
} db_LCKCON;

static union {
	UBYTE x;
	struct {
		unsigned LBAR	:7;
		unsigned 	:1;
	} anon;
} db_LLBAR;

static union {
	UBYTE x;
	struct {
		unsigned OTC	:8;
	} anon;
} db_LOTCR;

static union {
	UBYTE x;
	struct {
		unsigned POS	:3;
		unsigned BOS	:1;
		unsigned 	:4;
	} anon;
} db_LPOSR;

static union {
	UBYTE x;
	struct {
		unsigned YMOD	:4;
		unsigned XMOD	:4;
	} anon;
} db_LFRCM;

static union {
	UWORD x;
	struct {
		unsigned G2	:4;
		unsigned G3	:4;
		unsigned G0	:4;
		unsigned G1	:4;
	} anon;
} db_LGPMR;

static union {
	ULONG x;
	struct {
		unsigned SECONDS	:6;
		unsigned 	:10;
		unsigned MINUTES	:6;
		unsigned 	:2;
		unsigned HOURS	:5;
		unsigned 	:3;
	} anon;
} db_RTCHMS, db_RTCALARM;

static union {
	UBYTE x;
	struct {
		unsigned 	:5;
		unsigned REF384	:1;
		unsigned 	:1;
		unsigned ENABLE	:1;
	} anon;
} db_RTCCTL;

static union {
	UBYTE x;
	struct {
		unsigned SW	:1;
		unsigned MININT	:1;
		unsigned ALARM	:1;
		unsigned HOUR24	:1;
		unsigned HZ1	:1;
		unsigned 	:3;
	} anon;
} db_RTCISR, db_RTCIENR;

static shared_img *CustShptr = 0;

static union {
	UWORD	x;
	struct {
#ifdef WORDS_BIGENDIAN
		unsigned FIFO_FULL	:1;
		unsigned FIFO_HALF	:1;
		unsigned DATA_READY	:1;
		unsigned unused		:1;
		unsigned OVRUN		:1;
		unsigned FRAME_ERROR	:1;
		unsigned BREAK		:1;
		unsigned PARITY_ERROR	:1;
		unsigned DATA		:8;
#else /* not WORDS_BIGENDIAN */
		unsigned DATA		:8;
		unsigned PARITY_ERROR	:1;
		unsigned BREAK		:1;
		unsigned FRAME_ERROR	:1;
		unsigned OVRUN		:1;
		unsigned unused		:1;
		unsigned DATA_READY	:1;
		unsigned FIFO_HALF	:1;
		unsigned FIFO_FULL	:1;
#endif /* not WORDS_BIGENDIAN */
	} anon;
} db_URXdb;
static UWORD	db_TSTAT1_lastseen;
static UWORD	db_TSTAT2_lastseen;
static UBYTE	db_PDDATA_edge;

static unsigned long cycles;

#if 0
static int pendown = 0;
static int penx;
static int peny;
#endif

/*
 * Exported variable
 */
unsigned long specialflags;

static void
db_reset(void)
{
	db_SCR.x = 0x0c;
	db_GRPBASEA.x = 0x0000;
	db_GRPBASEC.x = 0x0000;
	db_GRPMASKA.x = 0x0000;
	db_GRPMASKC.x = 0x0000;
	db_CSA0.x = 0x00010006;
	db_CSA1.x = 0x00010006;
	db_CSA2.x = 0x00010006;
	db_CSA3.x = 0x00010006;
	db_CSC0.x = 0x00010006;
	db_CSC1.x = 0x00010006;
	db_CSC2.x = 0x00010006;
	db_CSC3.x = 0x00010006;
	db_PLLCR.x = 0x2400;
	db_PLLFSR.x = 0x0123;
	db_PCTLR.x = 0x1f;
	db_IVR.x = 0x00;
	db_ICR.x = 0x0000;
	db_IMR.x = 0x00ffffff;
	db_IWR.x = 0x00ffffff;
	db_ISR.x = 0x00000000;
	db_IPR.x = 0x00000000;
	db_PCDIR.x = 0x00;
	db_PCDATA.x = 0x00;
	db_PCSEL.x = 0x00;
	db_PDDIR.x = 0x00;
	db_PDDATA.x = 0x00;
	db_PDPUEN.x = 0xff;
	db_PDPOL.x = 0x00;
	db_PDIRQEN.x = 0x00;
	db_PDIRQEDGE.x = 0x00;
	db_PEDIR.x = 0x00;
	db_PEDATA.x = 0x00;
	db_PEPUEN.x = 0x80;
	db_PESEL.x = 0x80;
	db_PFDIR.x = 0x00;
	db_PFDATA.x = 0x00;
	db_PFPUEN.x = 0xff;
	db_PFSEL.x = 0xff;
	db_PGDIR.x = 0x00;
	db_PGDATA.x = 0x00;
	db_PGPUEN.x = 0xff;
	db_PGSEL.x = 0xff;
	db_PJDIR.x = 0x00;
	db_PJDATA.x = 0x00;
	db_PJSEL.x = 0x00;
	db_PKDIR.x = 0x00;
	db_PKDATA.x = 0x00;
	db_PKPUEN.x = 0x3f;
	db_PKSEL.x = 0x3f;
	db_PMDIR.x = 0x00;
	db_PMDATA.x = 0x00;
	db_PMPUEN.x = 0xff;
	db_PMSEL.x = 0x02;
	db_PWMC.x = 0x0000;
	db_PWMP.x = 0x0000;
	db_PWMW.x = 0x0000;
	db_TCTL1.x = 0x0000;
	db_TPRER1.x = 0x0000;
	db_TCMP1.x = 0xffff;
	db_TCN1.x = 0x0000;
	db_TSTAT1.x = 0x0000;
	db_TCTL2.x = 0x0000;
	db_TPRER2.x = 0x0000;
	db_TCMP2.x = 0xffff;
	db_TCN2.x = 0x0000;
	db_TSTAT2.x = 0x0000;
	db_WCSR.x = 0x0001;
	db_WCN.x = 0x0000;
	db_SPIMDATA.x = 0x0000;
	db_SPIMCONT.x = 0x0000;
	db_USTCNT.x = 0x0000;
	db_UBAUD.x = 0x003f;
	db_URX.x = 0x0000;
	db_UTX.x = 0x0000;
	db_UMISC.x = 0x0000;
	db_LSSA.x = 0x00000000;
	db_LVPW.x = 0xff;
	db_LXMAX.x = 0x03ff;
	db_LYMAX.x = 0x01ff;
	db_LCXP.x = 0x0000;
	db_LCYP.x = 0x0000;
	db_LCWCH.x = 0x0101;
	db_LBLKC.x = 0x7f;
	db_LPICF.x = 0x00;
	db_LPOLCF.x = 0x00;
	db_LPXCD.x = 0x00;
	db_LCKCON.x = 0x40;
	db_LLBAR.x = 0x3e;
	db_LOTCR.x = 0x3f;
	db_LPOSR.x = 0x00;
	db_LFRCM.x = 0xb9;
	db_LGPMR.x = 0x1073;
	db_RTCHMS.x = 0x00000000;
	db_RTCALARM.x = 0x00000000;
	db_RTCCTL.x = 0x00;
	db_RTCISR.x = 0x00;
	db_RTCIENR.x = 0x00;
}

void
customreset(void)
{
	cycles = 0;
	specialflags = 0;

	db_TSTAT1_lastseen = 0x0000;
	db_TSTAT2_lastseen = 0x0000;
	db_PDDATA_edge = 0x00;

	db_URXdb.x = 0x0000;

	db_reset();
}


/****************************************
 * Handle a key event. The fields	*
 * keydown and key of the shared image	*
 * are interpreted, and the dragonball	*
 * registers updated			*
 ****************************************/
static void
dokey(void)
{
	UBYTE		d;
	d = db_PDDATA.x;
	if (CustShptr->keydown) {
		db_PDDATA.x |= (1 << CustShptr->key);
		CustShptr->keydown = 0;
		CustShptr->key = -1;
	} else if (CustShptr->key >= 0) {
		db_PDDATA.x &= ~(1 << CustShptr->key);
		CustShptr->key = -1;
	}
	db_PDDATA_edge |= db_PDDATA.x & ~d;
	db_IPR.anon.PEN = CustShptr->pen;
	db_IPR.x = (db_IPR.x & 0xffff00ff) |
		((((db_PDDATA_edge & db_PDIRQEDGE.x) |
		   (db_PDDATA.x & ~db_PDIRQEDGE.x)) & db_PDIRQEN.x) << 8);
}

void
updateisr()
{
	db_IPR.anon.PEN = CustShptr->pen;
	db_ISR.x = db_IPR.x & ~db_IMR.x;
	if (db_ISR.x) {
		specialflags |= SPCFLAG_INT;
	}
	CustShptr->run_updateisr = 0;
}

void
maybe_updateisr()
{
	if (CustShptr->run_updateisr) {
		dokey();
		updateisr();
	}
}

int
intbase()
{
	return db_IVR.anon.VECTOR << 3;
}

int
intlev()
{
	if (db_ISR.anon.IRQ7)	return 7;
	if (db_ISR.anon.SPIS)	return 6;
	if (db_ISR.anon.TMR1)	return 6;
	if (db_ISR.anon.IRQ6)	return 6;
	if (db_ISR.anon.PEN)	return 5;
	if (db_ISR.anon.SPIM)	return 4;
	if (db_ISR.anon.TMR2)	return 4;
	if (db_ISR.anon.UART)	return 4;
	if (db_ISR.anon.WDT)	return 4;
	if (db_ISR.anon.RTC)	return 4;
	if (db_ISR.anon.KB)	return 4;
	if (db_ISR.anon.PWM)	return 4;
	if (db_ISR.anon.INT0)	return 4;
	if (db_ISR.anon.INT1)	return 4;
	if (db_ISR.anon.INT2)	return 4;
	if (db_ISR.anon.INT3)	return 4;
	if (db_ISR.anon.INT4)	return 4;
	if (db_ISR.anon.INT5)	return 4;
	if (db_ISR.anon.INT6)	return 4;
	if (db_ISR.anon.INT7)	return 4;
	if (db_ISR.anon.IRQ3)	return 3;
	if (db_ISR.anon.IRQ2)	return 2;
	if (db_ISR.anon.IRQ1)	return 1;
	return -1;
}

#if 0
static void
pen(int down, int x, int y)
{
	if (!pendown && down) {
		db_IPR.anon.PEN = 1;
		updateisr();
	} else if (pendown && !down) {
		db_IPR.anon.PEN = 0;
		updateisr();
	}
	pendown = down;
	penx = x;
	peny = y;
}

static void
hotsync(int down)
{
	if (down) {
		db_IPR.anon.IRQ1 = 1;
	} else {
		db_IPR.anon.IRQ1 = 0;
	}
	updateisr();
}
#endif

/*
 * custptr is a pointer to a shared memory block which will "back-up"
 * the register values of the custom circuits, allowing other processes
 * to look at register values
 */
void
custom_init(shared_img * shptr)
{
	CustShptr = shptr;
	CustShptr->PICF = 0;
	CustShptr->VPW = 0xff;
	CustShptr->POSR = 0;
	CustShptr->grpalette[0] = 1;
	CustShptr->grpalette[1] = 0;
	CustShptr->grpalette[2] = 3;
	CustShptr->grpalette[3] = 7;
	CustShptr->quit = 0;
	CustShptr->run_updateisr = 0;
	CustShptr->LcdPower = lcdOn;
	CustShptr->Backlight = 0;
	customreset();
}

void
do_cycles(int longtime)
{
	if (db_TCTL2.anon.TEN) {
		db_TCN2.anon.COUNT++;
		if (db_TCN2.anon.COUNT > db_TCMP2.anon.COMPARE || longtime) {
			db_TSTAT2.anon.COMP = 1;
			if (db_TCTL2.anon.FRR == 0) {
				db_TCN2.anon.COUNT = 0;
			}
			if (db_TCTL2.anon.IRQEN) {
				db_IPR.anon.TMR2 = 1;
				updateisr();
			}
		}
	}
	/*
	 * Determine if there are any chars to read from the serial port or
	 * debugger
	 */

	/*
	 * WARNING: This uses a shared memory data structure to store the
	 * FIFO. The producer is adding things to this _at the same time_ as
	 * this is consuming.  Examine main.c and take a course in concurrent
	 * programming before modifying this.  :-) - Ian
	 */

	if (CustShptr->serial.head != CustShptr->serial.tail &&
	    db_USTCNT.anon.UART_ENABLE && !db_URX.anon.DATA_READY) {
		int	curhead = CustShptr->serial.head;
		db_URX.anon.DATA = CustShptr->serial.fifo[curhead];
		curhead += 1;
		if (curhead == FIFO_SIZE) {
			curhead = 0;
		}
		CustShptr->serial.head = curhead;
		db_URX.anon.DATA_READY = 1;
		if (db_USTCNT.anon.RX_READY_ENABLE) {
			db_IPR.anon.UART = 1;
			updateisr();
		}
	}
	if (CustShptr->gdb.head != CustShptr->gdb.tail &&
	    db_USTCNT.anon.UART_ENABLE && !db_URXdb.anon.DATA_READY) {
		int	curhead = CustShptr->gdb.head;
		db_URXdb.anon.DATA = CustShptr->gdb.fifo[curhead];
		curhead += 1;
		if (curhead == FIFO_SIZE) {
			curhead = 0;
		}
		CustShptr->gdb.head = curhead;
		db_URXdb.anon.DATA_READY = 1;
	}
}

struct EventType {
	UWORD	eType;
	UWORD	penDown;
	UWORD	screenX;
	UWORD	screenY;
	UWORD	data[8];
};

struct SndCommandType {
	UWORD	cmd;
	UWORD	param1hi;
	UWORD	param1lo;
	UWORD	param2;
	UWORD	param3;
};

#define keyDownEvent		4
#define sysTrapEvtGetEvent	41245
#define sysTrapSndDoCmd		41523

int
do_api(int api)
{
	switch (api) {
		case sysTrapEvtGetEvent:
		if (CustShptr->kbin != CustShptr->kbout) {

			struct EventType	*ev;
			int			out;

			out = CustShptr->kbout;
			ev = (struct EventType *) get_real_address(get_long(CustShptr->regs.a[7]));

			ev->eType = keyDownEvent;
			ev->data[0] = CustShptr->kb[out];
			ev->data[1] = 0;
			ev->data[2] = 0;
			CustShptr->kbout = (out + 1) & 15;
			return 1;
		}
		break;
	case sysTrapSndDoCmd:
		{
			struct SndCommandType *sc;
			sc = (struct SndCommandType *)
				get_real_address(get_long(CustShptr->regs.a[7] + 4));
			if ((sc->cmd >> 8) == 1) {
				CustShptr->BellFreq = (sc->param1hi << 16) + sc->param1lo;
				CustShptr->BellDur = sc->param2;
				CustShptr->BellAmp = sc->param3;
				CustShptr->LcdReq = lcdBell;
				return 1;
			}
		}
		break;
	}
	return 0;
}

static ULONG
custom_lget(CPTR addr)
{
	switch (addr & 0xffff) {
	case CSA0:
		return db_CSA0.x;
	case CSA1:
		return db_CSA1.x;
	case CSA2:
		return db_CSA2.x;
	case CSA3:
		return db_CSA3.x;
	case CSC0:
		return db_CSC0.x;
	case CSC1:
		return db_CSC1.x;
	case CSC2:
		return db_CSC2.x;
	case CSC3:
		return db_CSC3.x;
	case IMR:
		return db_IMR.x;
	case IWR:
		return db_IWR.x;
	case ISR:
		return db_ISR.x;
	case IPR:
		db_IPR.anon.PEN = CustShptr->pen;
		return db_IPR.x;
	case LSSA:
		return db_LSSA.x;
	case RTCHMS:
		{
			struct tm	*st;
			time_t		t;
			t = time(0);
			st = localtime(&t);
			db_RTCHMS.anon.HOURS = st->tm_hour;
			db_RTCHMS.anon.MINUTES = st->tm_min;
			db_RTCHMS.anon.SECONDS = st->tm_sec;
		}
		return db_RTCHMS.x;
	case RTCALARM:
		return db_RTCALARM.x;
	default:
		fatal();
		return 0;
	}
}

static void
custom_lput(CPTR addr, ULONG value)
{
	switch (addr & 0xffff) {
	case CSA0:
		db_CSA0.x = value;
		break;
	case CSA1:
		db_CSA1.x = value;
		sram_protect = (value & 0x0008) != 0;
		break;
	case CSA2:
		db_CSA2.x = value;
		break;
	case CSA3:
		db_CSA3.x = value;
		break;
	case CSC0:
		db_CSC0.x = value;
		break;
	case CSC1:
		db_CSC1.x = value;
		break;
	case CSC2:
		db_CSC2.x = value;
		break;
	case CSC3:
		db_CSC3.x = value;
		break;
	case IMR:
		db_IMR.x = value;
		updateisr();
		break;
	case IWR:
		db_IWR.x = value;
		break;
	case ISR:
		if (db_ICR.anon.ET1 && (value & 0x00010000)) {
			db_IPR.anon.IRQ1 = 0;
			updateisr();
		}
		if (db_ICR.anon.ET2 && (value & 0x00020000)) {
			db_IPR.anon.IRQ2 = 0;
			updateisr();
		}
		if (db_ICR.anon.ET3 && (value & 0x00040000)) {
			db_IPR.anon.IRQ3 = 0;
			updateisr();
		}
		if (db_ICR.anon.ET6 && (value & 0x00080000)) {
			db_IPR.anon.IRQ6 = 0;
			updateisr();
		}
		if (value & 0x00800000) {
			db_IPR.anon.IRQ7 = 0;
			updateisr();
		}
		break;
	case IPR:
		/* do nothing */
		break;
	case LSSA:
		db_LSSA.x = value;
		CustShptr->lssa = value;
		break;
	case RTCHMS:
		db_RTCHMS.x = value;
		break;
	case RTCALARM:
		db_RTCALARM.x = value;
		break;
	default:
		fatal();
		break;
	}
}

static UWORD
custom_wget(CPTR addr)
{
	switch (addr & 0xffff) {
	case GRPBASEA:
		return db_GRPBASEA.x;
	case GRPBASEC:
		return db_GRPBASEC.x;
	case GRPMASKA:
		return db_GRPMASKA.x;
	case GRPMASKC:
		return db_GRPMASKC.x;
	case PLLCR:
		return db_PLLCR.x;
	case PLLFSR:
		db_PLLFSR.anon.CLK32 ^= 1;
		return db_PLLFSR.x;
	case ICR:
		return db_ICR.x;
	case IMR:
		return db_IMR.x >> 16;
	case IMR + 2:
		return db_IMR.x;
	case IWR:
		return db_IWR.x >> 16;
	case IWR + 2:
		return db_IWR.x;
	case ISR:
		return db_ISR.x >> 16;
	case ISR + 2:
		return db_ISR.x;
	case IPR:
		db_IPR.anon.PEN = CustShptr->pen;
		return db_IPR.x >> 16;
	case PWMC:
		return db_PWMC.x;
	case PWMP:
		return db_PWMP.x;
	case PWMW:
		return db_PWMW.x;
	case TCTL1:
		return db_TCTL1.x;
	case TPRER1:
		return db_TPRER1.x;
	case TCMP1:
		return db_TCMP1.x;
	case TSTAT1:
		db_TCN1.anon.COUNT += 16;
		if (db_TCN1.anon.COUNT - db_TCMP1.anon.COMPARE < 16) {
			db_TSTAT1.anon.COMP = 1;
			if (db_TCTL1.anon.FRR == 0) {
				db_TCN1.anon.COUNT = 0;
			}
		}
		db_TSTAT1_lastseen |= db_TSTAT1.x;
		return db_TSTAT1.x;
	case TCTL2:
		return db_TCTL2.x;
	case TPRER2:
		return db_TPRER2.x;
	case TCMP2:
		return db_TCMP2.x;
	case TSTAT2:
		db_TSTAT2_lastseen |= db_TSTAT2.x;
		return db_TSTAT2.x;
	case WCSR:
		return db_WCSR.x;
	case WCN:
		return db_WCN.x;
	case SPIMDATA:
		return db_SPIMDATA.x;
	case SPIMCONT:
		return db_SPIMCONT.x;
	case USTCNT:
		return db_USTCNT.x;
	case UBAUD:
		return db_UBAUD.x;
	case URX:
		if (DEBUGGER_READING) {
			db_URXdb.anon.DATA_READY = 0;
			return db_URXdb.x;
		} else {
			db_URX.anon.DATA_READY = 0;
			db_IPR.anon.UART = 0;
			updateisr();
			return db_URX.x;
		}
	case UTX:
		db_UTX.anon.FIFO_EMPTY = 1;
		db_UTX.anon.FIFO_HALF = 1;
		db_UTX.anon.TX_AVAIL = 1;
		db_UTX.anon.CTS_STATUS = 1;
		return db_UTX.x;
	case UMISC:
		return db_UMISC.x;
	case LXMAX:
		return db_LXMAX.x;
	case LYMAX:
		return db_LYMAX.x;
	case LCXP:
		return db_LCXP.x;
	case LCYP:
		return db_LCYP.x;
	case LCWCH:
		return db_LCWCH.x;
	case LGPMR:
		return db_LGPMR.x;
	case RTCCTL:
		return db_RTCCTL.x;
	case RTCISR:
		return db_RTCISR.x;
	case RTCIENR:
		return db_RTCIENR.x;
	default:
		fatal();
		return 0;
	}
}

static void
custom_wput(CPTR addr, UWORD value)
{
	switch (addr & 0xffff) {
	case GRPBASEA:
		db_GRPBASEA.x = value;
		break;
	case GRPBASEC:
		db_GRPBASEC.x = value;
		break;
	case GRPMASKA:
		db_GRPMASKA.x = value;
		break;
	case GRPMASKC:
		db_GRPMASKC.x = value;
		break;
	case PLLCR:
		db_PLLCR.x = value;
		break;
	case PLLFSR:
		db_PLLFSR.x = value;
		break;
	case ICR:
		db_ICR.x = value;
		break;
	case IMR:
		db_IMR.x &= 0x0000ffff;
		db_IMR.x |= value << 16;
		updateisr();
		break;
	case IMR + 2:
		db_IMR.x &= 0xffff0000;
		db_IMR.x |= value;
		updateisr();
		break;
	case IWR:
		db_IWR.x &= 0x0000ffff;
		db_IWR.x |= value << 16;
		break;
	case IWR + 2:
		db_IWR.x &= 0xffff0000;
		db_IWR.x |= value;
		break;
	case ISR:
		if (db_ICR.anon.ET1 && (value & 0x0001)) {
			db_IPR.anon.IRQ1 = 0;
			updateisr();
		}
		if (db_ICR.anon.ET2 && (value & 0x0002)) {
			db_IPR.anon.IRQ2 = 0;
			updateisr();
		}
		if (db_ICR.anon.ET3 && (value & 0x0004)) {
			db_IPR.anon.IRQ3 = 0;
			updateisr();
		}
		if (db_ICR.anon.ET6 && (value & 0x0008)) {
			db_IPR.anon.IRQ6 = 0;
			updateisr();
		}
		if (value & 0x0080) {
			db_IPR.anon.IRQ7 = 0;
			updateisr();
		}
		break;
	case ISR + 2:
		/* updateisr(); */
		break;
	case PWMC:
		db_PWMC.x = value;
		break;
	case PWMP:
		db_PWMP.x = value;
		break;
	case PWMW:
		db_PWMW.x = value;
		break;
	case TCTL1:
		db_TCTL1.x = value;
		break;
	case TPRER1:
		db_TPRER1.x = value;
		break;
	case TCMP1:
		db_TCMP1.x = value;
		break;
	case TSTAT1:
		db_TSTAT1.x = db_TSTAT1.x & (value | ~db_TSTAT1_lastseen);
		db_TSTAT1_lastseen = 0;
		if (db_TSTAT1.anon.COMP == 0) {
			db_IPR.anon.TMR1 = 0;
			updateisr();
		}
		break;
	case TCTL2:
		db_TCTL2.x = value;
		break;
	case TPRER2:
		db_TPRER2.x = value;
		break;
	case TCMP2:
		db_TCMP2.x = value;
		break;
	case TSTAT2:
		db_TSTAT2.x = db_TSTAT2.x & (value | ~db_TSTAT2_lastseen);
		db_TSTAT2_lastseen = 0;
		if (db_TSTAT2.anon.COMP == 0) {
			db_IPR.anon.TMR2 = 0;
			updateisr();
		}
		break;
	case WCSR:
		db_WCSR.x = value;
		break;
	case WCN:
		db_WCN.x = 0;
		break;
	case SPIMDATA:
		db_SPIMDATA.x = value;
		break;
	case SPIMCONT:
		db_SPIMCONT.x = value;
		if (db_SPIMCONT.anon.XCH && db_SPIMCONT.anon.IRQEN) {
			db_SPIMCONT.anon.SPIMIRQ = 1;
			db_SPIMCONT.anon.XCH = 0;
			switch (db_PFDATA.x & 0x0f) {
			case 0x6:
				db_SPIMDATA.x = (0xff - CustShptr->penx) * 2;
				break;
			case 0x9:
				db_SPIMDATA.x = (0xff - CustShptr->peny) * 2;
				break;
			}
		}
		break;
	case USTCNT:
		db_USTCNT.x = value;
		CustShptr->serial_flags = (db_USTCNT.anon.PARITY_ENABLE << 3) |
			(db_USTCNT.anon.ODD_EVEN << 2) | (db_USTCNT.anon.STOP_BITS << 1) |
			(db_USTCNT.anon.BITS_8);
		break;
	case UBAUD:
		db_UBAUD.x = value;
		CustShptr->serial_baud = 1036800 / (1 << db_UBAUD.anon.DIVIDE) /
			(65 - db_UBAUD.anon.PRESCALER);
		break;
	case URX:
		/* ignore db_URX.x = value; */
		break;
	case UTX:
		db_UTX.x = value;
		if (db_UMISC.anon.LOOP) {
			if (DEBUGGER_WRITING) {
				db_URXdb.anon.DATA = db_UTX.anon.DATA;
				db_URXdb.anon.DATA_READY = 1;
			} else {
				db_URX.anon.DATA = db_UTX.anon.DATA;
				db_URX.anon.DATA_READY = 1;
				if (db_USTCNT.anon.RX_READY_ENABLE) {
					db_IPR.anon.UART = 1;
					updateisr();
				}
			}
		} else {
			unsigned char	outbuf = value & 0xff;
			int		fd = (DEBUGGER_WRITING) ? CustShptr->gdb_writefd : CustShptr->serial_writefd;
			write(fd, &outbuf, 1);
		}
		break;
	case UMISC:
		db_UMISC.x = value;
		break;
	case LXMAX:
		db_LXMAX.x = value;
		break;
	case LYMAX:
		db_LYMAX.x = value;
		break;
	case LCXP:
		db_LCXP.x = value;
		break;
	case LCYP:
		db_LCYP.x = value;
		break;
	case LCWCH:
		db_LCWCH.x = value;
		break;
	case LGPMR:
		db_LGPMR.x = value;
		CustShptr->grpalette[0] = db_LGPMR.anon.G0;
		CustShptr->grpalette[1] = db_LGPMR.anon.G1;
		CustShptr->grpalette[2] = db_LGPMR.anon.G2;
		CustShptr->grpalette[3] = db_LGPMR.anon.G3;
		break;
	case RTCCTL:
		db_RTCCTL.x = (UBYTE) value;
		break;
	case RTCISR:
		db_RTCISR.x &= ~(UBYTE) value;
		break;
	case RTCIENR:
		db_RTCIENR.x = (UBYTE) value;
		break;
	default:
		fatal();
		break;
	}
}

static UBYTE
custom_bget(CPTR addr)
{
	switch (addr & 0xffff) {
	case SCR:
		return db_SCR.x;
	case PCTLR:
		return db_PCTLR.x;
	case IVR:
		return db_IVR.x;
	case PCDIR:
		return db_PCDIR.x;
	case PCDATA:
		db_PCDATA.anon.NMI = 1;	/* who knows, this makes the power on key work */
		return db_PCDATA.x;
	case PCSEL:
		return db_PCSEL.x;
	case PDDIR:
		return db_PDDIR.x;
	case PDDATA:
		return db_PDDATA.x;
	case PDPUEN:
		return db_PDPUEN.x;
	case PDPOL:
		return db_PDPOL.x;
	case PDIRQEN:
		return db_PDIRQEN.x;
	case PDIRQEDGE:
		return db_PDIRQEDGE.x;
	case PEDIR:
		return db_PEDIR.x;
	case PEDATA:
		return db_PEDATA.x;
	case PEPUEN:
		return db_PEPUEN.x;
	case PESEL:
		return db_PESEL.x;
	case PFDIR:
		return db_PFDIR.x;
	case PFDATA:
		return db_PFDATA.x;
	case PFPUEN:
		return db_PFPUEN.x;
	case PFSEL:
		return db_PFSEL.x;
	case PGDIR:
		return db_PGDIR.x;
	case PGDATA:
		return db_PGDATA.x;
	case PGPUEN:
		return db_PGPUEN.x;
	case PGSEL:
		return db_PGSEL.x;
	case PJDIR:
		return db_PJDIR.x;
	case PJDATA:
		return db_PJDATA.x;
	case PJSEL:
		return db_PJSEL.x;
	case PKDIR:
		return db_PKDIR.x;
	case PKDATA:
		return db_PKDATA.x;
	case PKPUEN:
		return db_PKPUEN.x;
	case PKSEL:
		return db_PKSEL.x;
	case PMDIR:
		return db_PMDIR.x;
	case PMDATA:
		return db_PMDATA.x;
	case PMPUEN:
		return db_PMPUEN.x;
	case PMSEL:
		return db_PMSEL.x;
	case PWMC:
		return db_PWMC.x >> 8;
	case PWMC + 1:
		return db_PWMC.x;
	case URX:
		if (DEBUGGER_READING) {
			return db_URXdb.x >> 8;
		} else {
			return db_URX.x >> 8;
		}
	case LVPW:
		return db_LVPW.x;
	case LBLKC:
		return db_LBLKC.x;
	case LPICF:
		return db_LPICF.x;
	case LPOLCF:
		return db_LPOLCF.x;
	case LPXCD:
		return db_LPXCD.x;
	case LCKCON:
		return db_LCKCON.x;
	case LLBAR:
		return db_LLBAR.x;
	case LOTCR:
		return db_LOTCR.x;
	case LPOSR:
		return db_LPOSR.x;
	case LFRCM:
		return db_LFRCM.x;
	case RTCCTL:
		return db_RTCCTL.x;
	case RTCISR:
		return db_RTCISR.x;
	case RTCIENR:
		return db_RTCIENR.x;
	default:
		fatal();
		return 0;
	}
}

static void
custom_bput(CPTR addr, UBYTE value)
{
	switch (addr & 0xffff) {
	case SCR:
		db_SCR.x = value & ~(value & 0xe0);
		break;
	case PCTLR:
		db_PCTLR.x = value;
		break;
	case IVR:
		db_IVR.x = value;
		break;
	case PCDIR:
		db_PCDIR.x = value;
		break;
	case PCDATA:
		db_PCDATA.x = value;
		break;
	case PCSEL:
		db_PCSEL.x = value;
		break;
	case PDDIR:
		db_PDDIR.x = value;
		break;
	case PDDATA:
		db_PDDATA_edge &= ~value;
		db_IPR.anon.PEN = CustShptr->pen;
		db_IPR.x = (db_IPR.x & 0xffff00ff) |
			((((db_PDDATA_edge & db_PDIRQEDGE.x) |
			(db_PDDATA.x & ~db_PDIRQEDGE.x)) & db_PDIRQEN.x) << 8);
		updateisr();
		break;
	case PDPUEN:
		db_PDPUEN.x = value;
		break;
	case PDPOL:
		db_PDPOL.x = value;
		break;
	case PDIRQEN:
		db_PDIRQEN.x = value;
		db_IPR.anon.PEN = CustShptr->pen;
		db_IPR.x = (db_IPR.x & 0xffff00ff) |
			((((db_PDDATA_edge & db_PDIRQEDGE.x) |
			(db_PDDATA.x & ~db_PDIRQEDGE.x)) & db_PDIRQEN.x) << 8);
		updateisr();
		break;
	case PDIRQEDGE:
		db_PDIRQEDGE.x = value;
		break;
	case PEDIR:
		db_PEDIR.x = value;
		break;
	case PEDATA:
		db_PEDATA.x = value;
		break;
	case PEPUEN:
		db_PEPUEN.x = value;
		break;
	case PESEL:
		db_PESEL.x = value;
		break;
	case PFDIR:
		db_PFDIR.x = value;
		break;
	case PFDATA:
		db_PFDATA.x = value;
		break;
	case PFPUEN:
		db_PFPUEN.x = value;
		break;
	case PFSEL:
		db_PFSEL.x = value;
		break;
	case PGDIR:
		db_PGDIR.x = value;
		break;
	case PGDATA:
		db_PGDATA.x = value;
		CustShptr->Backlight = (value & 0x80);
		break;
	case PGPUEN:
		db_PGPUEN.x = value;
		break;
	case PGSEL:
		db_PGSEL.x = value;
		break;
	case PJDIR:
		db_PJDIR.x = value;
		break;
	case PJDATA:
		db_PJDATA.x = value;
		break;
	case PJSEL:
		db_PJSEL.x = value;
		break;
	case PKDIR:
		db_PKDIR.x = value;
		break;
	case PKDATA:
		db_PKDATA.x = value;
		break;
	case PKPUEN:
		db_PKPUEN.x = value;
		break;
	case PKSEL:
		db_PKSEL.x = value;
		break;
	case PMDIR:
		db_PMDIR.x = value;
		break;
	case PMDATA:
		db_PMDATA.x = value;
		break;
	case PMPUEN:
		db_PMPUEN.x = value;
		break;
	case PMSEL:
		db_PMSEL.x = value;
		break;
	case PWMC:
		db_PWMC.x &= 0x00ff;
		db_PWMC.x |= value << 8;
		break;
	case PWMC + 1:
		db_PWMC.x &= 0xff00;
		db_PWMC.x |= value;
		break;
	case UTX:
		abort();
		break;
	case UTX + 1:
		db_UTX.anon.DATA = value;
		if (db_UMISC.anon.LOOP) {
			if (DEBUGGER_WRITING) {
				db_URXdb.anon.DATA = db_UTX.anon.DATA;
				db_URXdb.anon.DATA_READY = 1;
			} else {
				db_URX.anon.DATA = db_UTX.anon.DATA;
				db_URX.anon.DATA_READY = 1;
				if (db_USTCNT.anon.RX_READY_ENABLE) {
					db_IPR.anon.UART = 1;
					updateisr();
				}
			}
		} else {
			unsigned char	outbuf = value & 0xff;
			int		fd = (DEBUGGER_WRITING) ? CustShptr->gdb_writefd : CustShptr->serial_writefd;
			write(fd, &outbuf, 1);
		}
		break;
	case LVPW:
		db_LVPW.x = value;
		CustShptr->VPW = value;
		break;
	case LBLKC:
		db_LBLKC.x = value;
		break;
	case LPICF:
		db_LPICF.x = value;
		CustShptr->PICF = value;
		break;
	case LPXCD:
		db_LPXCD.x = value;
		break;
	case LCKCON:
		db_LCKCON.x = value;
		CustShptr->LcdPower = db_LCKCON.anon.LCDCON ? lcdOn : lcdOff;
		break;
	case LLBAR:
		db_LLBAR.x = value;
		break;
	case LOTCR:
		db_LOTCR.x = value;
		break;
	case LPOSR:
		db_LPOSR.x = value;
		CustShptr->POSR = value;
		break;
	case LFRCM:
		db_LFRCM.x = value;
		break;
	case RTCCTL:
		db_RTCCTL.x = value;
		break;
	case RTCISR:
		db_RTCISR.x &= ~value;
		break;
	case RTCIENR:
		db_RTCIENR.x = value;
		break;
	default:
		fatal();
		break;
	}
}

addrbank custom_bank = {
	custom_lget, custom_wget, custom_bget,
	custom_lput, custom_wput, custom_bput,
	default_xlate, default_check
};

