/*****************************************************************************
 * $Id: fab_custom.c,v 1.2 1998/07/28 23:08:48 mcculley Exp $
 *
 * File:        fab.c
 *
 * Author:      Max Okumoto <okumoto@ucsd.edu>
 *
 * Abstract:    This program generates the code that simulates the dragonball's
 *              intelligent peripheral modules and system interface logic.
 *
 * Note:        All the registers have specified size and all simulated code
 *              should access the registers appropriately.  However we can't
 *              control what pilot programers do :-)  In these cases the
 *              *_get_xxx() and *_put_xxx() have to be written.
 *
 * 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 - Suite 330, Boston, MA 02111-1307, USA. 
 *****************************************************************************/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

#include "../config.h"

struct Fab;
struct Reg;

typedef void Reg_Op(struct Fab *, const struct Reg *);

typedef struct Fab {
	FILE	*f_c;	/* fp to generated custom.c file */
	FILE	*f_h;	/* fp to generated custom.h file */
	int	bo;	/* byte order */
#define FAB_LITTLEENDIAN	0
#define FAB_BIGENDIAN		1

	int	lvl;	/* indent level */
} Fab;

typedef const struct Reg {
	char	*name;			/* name of hardware register */
	int	addr;			/* address of hardware register */
	int	size;			/* size of hardware register */
	int	init;			/* reset value of hardware register */
	struct {
		Reg_Op	*get;
		Reg_Op	*put;
	} b;				/* byte operations */
	struct {
		Reg_Op	*get;
		Reg_Op	*put;
	} w;				/* word operations */
	struct {
		Reg_Op	*get;
		Reg_Op	*put;
	} l;				/* word operations */
	char	*fields;
} Reg;

/*---------------------------------------------------------------------------*
 * Helper functions
 *---------------------------------------------------------------------------*/

/*===========================================================================*
 * Function:	putln
 *
 * Abstract:	This function adds indention to each line.
 *
 * Note:	No state is kept between calls, so each fmt must contain
 *		complete lines.
 *===========================================================================*/
static void
putln(Fab *f, const char fmt[], ...)
{
	const char	*p;
	int		count;
	char		*new_fmt;
	char		*s;
	va_list		ap;

	va_start(ap, fmt);

	/*
	 * Calc the size of new_fmt string.  (fmt.len + #newlines * #lvl)
	 */
	count = 0;
	for (p = fmt; *p != '\0'; p++) {
		count += (*p == '\n') ? (1 + f->lvl) : 1;
	}
	new_fmt = malloc(count + 1 + f->lvl);
	s = new_fmt;

	/*
	 * Add tab characters to the begining of each line.
	 */
	if (fmt[0] == '\n' && fmt[1] == '\0') {
		/* do nothing */
	} else {
		int		i;
		for (i = 0; i < f->lvl; i++) *s++ = '\t';
	}
	for (p = fmt; *p != '\0'; p++) {
		*s++ = *p;
		if (p[0] == '\n' && p[1] != '\0' && p[1] != '\n') {
			int		i;
			for (i = 0; i < f->lvl; i++) *s++ = '\t';
		}
	}
	*s++ = '\0';

	/*
	 * Output line.
	 */
	vfprintf(f->f_c, new_fmt, ap);
	free(new_fmt);

	va_end(ap);
}

/*---------------------------------------------------------------------------*
 * Operation generators
 *---------------------------------------------------------------------------*/

/*
 * Generic
 */
static void
reg_get(Fab *f, Reg *r)
{
	putln(f,"return db_%s.x;\n", r->name);
}

static void
reg_put(Fab *f, Reg *r)
{
	putln(f,"db_%s.x = value;\n", r->name);
}

/*
 * System Control
 */
static void
scr_put(Fab *f, Reg *r)
{
	putln(f,"db_%s.x = value & ~(value & 0xe0);\n", r->name);
}

/*
 * Chip Select
 */
static void
csa1_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"sram_protect = (value & 0x0008) != 0;\n", r->name);
}

/*
 * Phase Locked Loop
 */
static void
pllfsr_get(Fab *f, Reg *r)
{
	putln(f,"db_%s.anon.CLK32 ^= 1;\n", r->name);
	reg_get(f, r);
}

/*
 * Interrupt controller
 */
static void
imr_get_xxx(Fab *f, Reg *r)
{
	putln(f,"return db_%s.x >> 16;\n", r->name);

	f->lvl -= 2;
	putln(f,"	case %s + 2:\n", r->name);
	f->lvl += 2;

	putln(f,"return db_%s.x;\n", r->name);
}

static void
imr_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"updateisr();\n", r->name);
}

static void
imr_put_xxx(Fab *f, Reg *r)
{
	putln(f,"db_%s.x &= 0x0000ffff;\n", r->name);
	putln(f,"db_%s.x |= value << 16;\n", r->name);
	putln(f,"updateisr();\n", r->name);

	putln(f,"break;\n");
	f->lvl -= 2;
	putln(f,"	case %s + 2:\n", r->name);
	f->lvl += 2;

	putln(f,"db_%s.x &= 0xffff0000;\n", r->name);
	putln(f,"db_%s.x |= value;\n", r->name);
	putln(f,"updateisr();\n", r->name);
}

static void
iwr_get_xxx(Fab *f, Reg *r)
{
	putln(f,"return db_%s.x >> 16;\n", r->name);

	f->lvl -= 2;
	putln(f,"	case %s + 2:\n", r->name);
	f->lvl += 2;

	putln(f,"return db_%s.x;\n", r->name);
}

static void
iwr_put_xxx(Fab *f, Reg *r)
{
	putln(f,"db_%s.x &= 0x0000ffff;\n", r->name);
	putln(f,"db_%s.x |= value << 16;\n", r->name);

	putln(f,"break;\n");
	f->lvl -= 2;
	putln(f,"	case %s + 2:\n", r->name);
	f->lvl += 2;

	putln(f,"db_%s.x &= 0xffff0000;\n", r->name);
	putln(f,"db_%s.x |= value;\n", r->name);
}

static void
isr_get_xxx(Fab *f, Reg *r)
{
	putln(f,"return db_%s.x >> 16;\n", r->name);

	f->lvl -= 2;
	putln(f,"	case %s + 2:\n", r->name);
	f->lvl += 2;

	putln(f,"return db_%s.x;\n", r->name);
}

static void
isr_put(Fab *f, Reg *r)
{
	putln(f,"if (db_ICR.anon.ET1 && (value & 0x00010000)) {\n"
		"	db_IPR.anon.IRQ1 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (db_ICR.anon.ET2 && (value & 0x00020000)) {\n"
		"	db_IPR.anon.IRQ2 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (db_ICR.anon.ET3 && (value & 0x00040000)) {\n"
		"	db_IPR.anon.IRQ3 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (db_ICR.anon.ET6 && (value & 0x00080000)) {\n"
		"	db_IPR.anon.IRQ6 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (value & 0x00800000) {\n"
		"	db_IPR.anon.IRQ7 = 0;\n"
		"	updateisr();\n"
		"}\n");
}

static void
isr_put_xxx(Fab *f, Reg *r)
{
	putln(f,"if (db_ICR.anon.ET1 && (value & 0x0001)) {\n"
		"	db_IPR.anon.IRQ1 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (db_ICR.anon.ET2 && (value & 0x0002)) {\n"
		"	db_IPR.anon.IRQ2 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (db_ICR.anon.ET3 && (value & 0x0004)) {\n"
		"	db_IPR.anon.IRQ3 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (db_ICR.anon.ET6 && (value & 0x0008)) {\n"
		"	db_IPR.anon.IRQ6 = 0;\n"
		"	updateisr();\n"
		"}\n"
		"if (value & 0x0080) {\n"
		"	db_IPR.anon.IRQ7 = 0;\n"
		"	updateisr();\n"
		"}\n");

	putln(f,"break;\n");
	f->lvl -= 2;
	putln(f,"	case %s + 2:\n", r->name);
	f->lvl += 2;

	putln(f,"/* updateisr(); */\n");
}

static void
ipr_get(Fab *f, Reg *r)
{
	putln(f,"db_%s.anon.PEN = CustShptr->pen;\n", r->name);
	reg_get(f, r);
}

static void
ipr_get_xxx(Fab *f, Reg *r)
{
	putln(f,"db_%s.anon.PEN = CustShptr->pen;\n", r->name);
	putln(f,"return db_%s.x >> 16;\n", r->name);
#if CHECKME
	f->lvl -= 2;
	putln(f,"	case %s + 2:\n", r->name);
	f->lvl += 2;

	putln(f,"db_%s.anon.PEN = CustShptr->pen;\n", r->name);
	putln(f,"return db_%s.x;\n", r->name);
#endif
}

static void
ipr_put(Fab *f, Reg *r)
{
	putln(f,"/* do nothing */\n", r->name);
}

/*
 * Parallel IO
 */
static void
pcdata_get(Fab *f, Reg *r)
{
	putln(f,"db_%s.anon.NMI = 1;	/* who knows, this makes the power on key work */\n", r->name);
	reg_get(f, r);
}

static void
pddata_put(Fab *f, Reg *r)
{
	putln(f,"db_PDDATA_edge &= ~value;\n"
		"db_IPR.anon.PEN = CustShptr->pen;\n"
		"db_IPR.x = (db_IPR.x & 0xffff00ff) |\n"
		"	((((db_PDDATA_edge & db_PDIRQEDGE.x) |\n"
		"	(db_PDDATA.x & ~db_PDIRQEDGE.x)) & db_PDIRQEN.x) << 8);\n"
		"updateisr();\n");
}

static void
pdirqen_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"db_IPR.anon.PEN = CustShptr->pen;\n"
		"db_IPR.x = (db_IPR.x & 0xffff00ff) |\n"
		"	((((db_PDDATA_edge & db_PDIRQEDGE.x) |\n"
		"	(db_PDDATA.x & ~db_PDIRQEDGE.x)) & db_PDIRQEN.x) << 8);\n"
		"updateisr();\n");
}

static void
pgdata_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->Backlight = (value & 0x80);\n");
}

/*
 * Pulse Width Modulator
 */
static void
pwmc_get_xxx(Fab *f, Reg *r)
{
	putln(f,"return db_%s.x >> 8;\n", r->name);

	f->lvl -= 2;
	putln(f,"	case %s + 1:\n", r->name);
	f->lvl += 2;

	putln(f,"return db_%s.x;\n", r->name);
}

static void
pwmc_put_xxx(Fab *f, Reg *r)
{
	putln(f,"db_%s.x &= 0x00ff;\n", r->name);
	putln(f,"db_%s.x |= value << 8;\n", r->name);

	putln(f,"break;\n");
	f->lvl -= 2;
	putln(f,"	case %s + 1:\n", r->name);
	f->lvl += 2;

	putln(f,"db_%s.x &= 0xff00;\n", r->name);
	putln(f,"db_%s.x |= value;\n", r->name);
}

/*
 * Timer
 */
static void
tstat1_get(Fab *f, Reg *r)
{
	putln(f,"db_TCN1.anon.COUNT += 16;\n"
		"if (db_TCN1.anon.COUNT - db_TCMP1.anon.COMPARE < 16) {\n"
		"	db_TSTAT1.anon.COMP = 1;\n"
		"	if (db_TCTL1.anon.FRR == 0) {\n"
		"		db_TCN1.anon.COUNT = 0;\n"
		"	}\n"
		"}\n"
		"db_TSTAT1_lastseen |= db_TSTAT1.x;\n");
	reg_get(f, r);
}

static void
tstat1_put(Fab *f, Reg *r)
{
	putln(f,"db_TSTAT1.x = db_TSTAT1.x & (value | ~db_TSTAT1_lastseen);\n"
		"db_TSTAT1_lastseen = 0;\n"
		"if (db_TSTAT1.anon.COMP == 0) {\n"
		"	db_IPR.anon.TMR1 = 0;\n"
		"	updateisr();\n"
		"}\n");
}

static void
tstat2_get(Fab *f, Reg *r)
{
	putln(f,"db_TSTAT2_lastseen |= db_TSTAT2.x;\n");
	reg_get(f, r);
}

static void
tstat2_put(Fab *f, Reg *r)
{
	putln(f,"db_TSTAT2.x = db_TSTAT2.x & (value | ~db_TSTAT2_lastseen);\n"
		"db_TSTAT2_lastseen = 0;\n"
		"if (db_TSTAT2.anon.COMP == 0) {\n"
		"	db_IPR.anon.TMR2 = 0;\n"
		"	updateisr();\n"
		"}\n");
}

/*
 * Watchdog
 */
static void
wcn_put(Fab *f, Reg *r)
{
	putln(f,"db_WCN.x = 0;\n");
}

/*
 * Serial Peripheral Interface Slave
 */

/*
 * Serial Peripheral Interface Master
 */
static void
spimcont_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"if (db_SPIMCONT.anon.XCH && db_SPIMCONT.anon.IRQEN) {\n"
		"	db_SPIMCONT.anon.SPIMIRQ = 1;\n"
		"	db_SPIMCONT.anon.XCH = 0;\n"
		"	switch (db_PFDATA.x & 0x0f) {\n"
		"	case 0x6:\n"
		"		db_SPIMDATA.x = (0xff - CustShptr->penx) * 2;\n"
		"		break;\n"
		"	case 0x9:\n"
		"		db_SPIMDATA.x = (0xff - CustShptr->peny) * 2;\n"
		"		break;\n"
		"	}\n"
		"}\n");
}

/*
 * UART Controller
 */
static void
ustcnt_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->serial_flags = (db_USTCNT.anon.PARITY_ENABLE << 3) |\n"
		"	(db_USTCNT.anon.ODD_EVEN << 2) | (db_USTCNT.anon.STOP_BITS << 1) |\n"
		"	(db_USTCNT.anon.BITS_8);\n");
}

static void
ubaud_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->serial_baud = 1036800 / (1 << db_UBAUD.anon.DIVIDE) /\n"
		"	(65 - db_UBAUD.anon.PRESCALER);\n");
}

static void
urx_get(Fab *f, Reg *r)
{
	putln(f,"if (DEBUGGER_READING) {\n"
		"	db_URXdb.anon.DATA_READY = 0;\n"
		"	return db_URXdb.x;\n"
		"} else {\n"
		"	db_URX.anon.DATA_READY = 0;\n"
		"	db_IPR.anon.UART = 0;\n"
		"	updateisr();\n"
		"	return db_URX.x;\n"
		"}\n");
}

static void
urx_get_xxx(Fab *f, Reg *r)
{
#if CHECKME
	putln(f,"if (DEBUGGER_READING) {\n"
		"	db_URXdb.anon.DATA_READY = 0;\n"
		"	return db_URXdb.x >> 8;\n"
		"} else {\n"
		"	db_URX.anon.DATA_READY = 0;\n"
		"	db_IPR.anon.UART = 0;\n"
		"	updateisr();\n"
		"	return db_URX.x >> 8;\n"
		"}\n");

	f->lvl -= 2;
	putln(f,"	case %s + 1:\n", r->name);
	f->lvl += 2;

	putln(f,"if (DEBUGGER_READING) {\n"
		"	db_URXdb.anon.DATA_READY = 0;\n"
		"	return db_URXdb.x;\n"
		"} else {\n"
		"	db_URX.anon.DATA_READY = 0;\n"
		"	db_IPR.anon.UART = 0;\n"
		"	updateisr();\n"
		"	return db_URX.x;\n"
		"}\n");
#else
	putln(f,"if (DEBUGGER_READING) {\n"
		"	return db_URXdb.x >> 8;\n"
		"} else {\n"
		"	return db_URX.x >> 8;\n"
		"}\n");
#endif
}

static void
urx_put(Fab *f, Reg *r)
{
	putln(f,"/* ignore db_URX.x = value; */\n");
}

static void
utx_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"if (db_UMISC.anon.LOOP) {\n"
		"	if (DEBUGGER_WRITING) {\n"
		"		db_URXdb.anon.DATA = db_UTX.anon.DATA;\n"
		"		db_URXdb.anon.DATA_READY = 1;\n"
		"	} else {\n"
		"		db_URX.anon.DATA = db_UTX.anon.DATA;\n"
		"		db_URX.anon.DATA_READY = 1;\n"
		"		if (db_USTCNT.anon.RX_READY_ENABLE) {\n"
		"			db_IPR.anon.UART = 1;\n"
		"			updateisr();\n"
		"		}\n"
		"	}\n"
		"} else {\n"
		"	unsigned char	outbuf = value & 0xff;\n"
		"	int		fd = (DEBUGGER_WRITING) ? CustShptr->gdb_writefd : CustShptr->serial_writefd;\n"
		"	write(fd, &outbuf, 1);\n"
		"}\n");
}

static void
utx_put_xxx(Fab *f, Reg *r)
{
	putln(f,"abort();\n");

	putln(f,"break;\n");
	f->lvl -= 2;
	putln(f,"	case %s + 1:\n", r->name);
	f->lvl += 2;

	putln(f,"db_%s.anon.DATA = value;\n", r->name);
	putln(f,"if (db_UMISC.anon.LOOP) {\n"
		"	if (DEBUGGER_WRITING) {\n"
		"		db_URXdb.anon.DATA = db_UTX.anon.DATA;\n"
		"		db_URXdb.anon.DATA_READY = 1;\n"
		"	} else {\n"
		"		db_URX.anon.DATA = db_UTX.anon.DATA;\n"
		"		db_URX.anon.DATA_READY = 1;\n"
		"		if (db_USTCNT.anon.RX_READY_ENABLE) {\n"
		"			db_IPR.anon.UART = 1;\n"
		"			updateisr();\n"
		"		}\n"
		"	}\n"
		"} else {\n"
		"	unsigned char	outbuf = value & 0xff;\n"
		"	int		fd = (DEBUGGER_WRITING) ? CustShptr->gdb_writefd : CustShptr->serial_writefd;\n"
		"	write(fd, &outbuf, 1);\n"
		"}\n");
}

static void
utx_get(Fab *f, Reg *r)
{
	putln(f,"db_UTX.anon.FIFO_EMPTY = 1;\n"
		"db_UTX.anon.FIFO_HALF = 1;\n"
		"db_UTX.anon.TX_AVAIL = 1;\n"
		"db_UTX.anon.CTS_STATUS = 1;\n");
	reg_get(f, r);
}

/*
 * LCD Controller
 */
static void
lssa_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->lssa = value;\n");
}

static void
lvpw_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->VPW = value;\n");
}

static void
lpicf_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->PICF = value;\n");
}

static void
lckcon_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->LcdPower = db_%s.anon.LCDCON ? lcdOn : lcdOff;\n", r->name);
}

static void
lposr_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->POSR = value;\n");
}

static void
lgpmr_put(Fab *f, Reg *r)
{
	reg_put(f, r);
	putln(f,"CustShptr->grpalette[0] = db_%s.anon.G0;\n", r->name);
	putln(f,"CustShptr->grpalette[1] = db_%s.anon.G1;\n", r->name);
	putln(f,"CustShptr->grpalette[2] = db_%s.anon.G2;\n", r->name);
	putln(f,"CustShptr->grpalette[3] = db_%s.anon.G3;\n", r->name);
}

/*
 * Real Time Clock
 */
static void
rhmsr_get(Fab *f, Reg *r)
{
	putln(f,"{\n"
		"	struct tm	*st;\n"
		"	time_t		t;\n"
		"	t = time(0);\n"
		"	st = localtime(&t);\n"
		"	db_RTCHMS.anon.HOURS = st->tm_hour;\n"
		"	db_RTCHMS.anon.MINUTES = st->tm_min;\n"
		"	db_RTCHMS.anon.SECONDS = st->tm_sec;\n"
		"}\n");
	reg_get(f, r);
}

static void
rctl_put_xxx(Fab *f, Reg *r)
{
	putln(f,"db_%s.x = (UBYTE) value;\n", r->name);
}

static void
risr_put(Fab *f, Reg *r)
{
	putln(f,"db_%s.x &= ~value;\n", r->name);
}

static void
risr_put_xxx(Fab *f, Reg *r)
{
	putln(f,"db_%s.x &= ~(UBYTE) value;\n", r->name);
}

static void
rienr_put_xxx(Fab *f, Reg *r)
{
	putln(f,"db_%s.x = (UBYTE) value;\n", r->name);
}

/*---------------------------------------------------------------------------*
 * Function generators
 *---------------------------------------------------------------------------*/
static void
gen_defs(Fab *f, Reg chip[])
{
	Reg	*r;

	for (r = chip; r->name != NULL; r++) {
		putln(f,"#define %s	0x%x\n", r->name, r->addr);
	}
	putln(f,"\n");
}

static void
gen_vars(Fab *f, Reg chip[])
{
	Reg	*r;

#define MAX_LEN		32
#define MAX_COUNT	32
	r = chip;
	while (r->name != NULL) {
		char	buff[1024];

		putln(f,"static union {\n");
		switch (r->size) {
		case 1: putln(f,"	UBYTE x;\n"); break;
		case 2: putln(f,"	UWORD x;\n"); break;
		case 4: putln(f,"	ULONG x;\n"); break;
		}

		/* print out bit fields for hardware register */
		{
			char	field[MAX_COUNT][MAX_LEN];
			char	*s;	/* source */
			char	*d;	/* dest */
			int	count;
			int	len;
			int	i;

			putln(f,"	struct {\n");
			/* break up fields into seperate strings */
			count = 0;
			s = r->fields;
			d = field[count];
			while (1) {
				if (*s == '\0') {
					*d++ = '\0';
					break;
				} else if (*s == ':') {
					*d++ = '\t';
					*d++ = *s;
				} else if (*s == ';') {
					*d++ = *s;
					*d++ = '\0';
					count++;
					d = field[count];
				} else {
					*d++ = *s;
				}
				s++;
			}

			/* output fields depending on byte order of target */
			switch (f->bo) {
			case FAB_BIGENDIAN:
				for (i = count - 1; i >= 0; i--) {
					putln(f,"		unsigned %s\n",
						field[i]);
				}
				break;
			case FAB_LITTLEENDIAN:
				for (i = 0; i < count; i++) {
					putln(f,"		unsigned %s\n",
						field[i]);
				}
				break;
			}
			putln(f,"	} anon;\n");
		}

		/* print out name of variables */
		{
			char	name[1024];
			char	*ptr = buff;
			char	*last_fields = r->fields;
			Reg	*next_r = r + 1;

			sprintf(ptr," db_%s", r->name);
			ptr += strlen(ptr);

			while (next_r->name != NULL) {
				if ((strcmp(next_r->fields, r->fields) == 0)
				    && (next_r->size == r->size)) {
					sprintf(ptr,", db_%s", next_r->name);
					ptr += strlen(ptr);
					next_r++;
				} else {
					break;
				}
			}
			r = next_r;
		}

		putln(f,"}%s;\n", buff);
		putln(f,"\n");
	}
}

static void
gen_init(Fab *f, Reg chip[])
{
	Reg	*r;

	putln(f,"static void\n"
		"db_reset(void)\n"
		"{\n");

	f->lvl++;
	for (r = chip; r->name != NULL; r++) {
		switch (r->size) {
		case 1:
			putln(f,"db_%s.x = 0x%02x;\n", r->name, r->init);
			break;
		case 2:
			putln(f,"db_%s.x = 0x%04x;\n", r->name, r->init);
			break;
		case 4:
			putln(f,"db_%s.x = 0x%08x;\n", r->name, r->init);
			break;
		}
	}
	f->lvl--;

	putln(f,"}\n"
		"\n");
}

void
gen_bget(Fab *f, Reg chip[])
{
	Reg	*r;

	putln(f,"static UBYTE\n"
		"custom_bget(CPTR addr)\n"
		"{\n"
		"	switch (addr & 0xffff) {\n");

	for (r = chip; r->name != NULL; r++) {
		if (r->b.get != 0) {
			putln(f,"	case %s:\n", r->name);
			f->lvl += 2;
			r->b.get(f, r);
			f->lvl -= 2;
		}
	}

	putln(f,"	default:\n"
		"		fatal();\n"
		"		return 0;\n"
		"	}\n"
		"}\n"
		"\n");
}

void
gen_bput(Fab *f, Reg chip[])
{
	Reg	*r;

	putln(f,"static void\n"
		"custom_bput(CPTR addr, UBYTE value)\n"
		"{\n"
		"	switch (addr & 0xffff) {\n");

	for (r = chip; r->name != NULL; r++) {
		if (r->b.put != 0) {
			putln(f,"	case %s:\n", r->name);
			f->lvl += 2;
			r->b.put(f, r);
			f->lvl -= 2;
			putln(f,"		break;\n");
		}
	}

	putln(f,"	default:\n"
		"		fatal();\n"
		"		break;\n"
		"	}\n"
		"}\n"
		"\n");
}


void
gen_wget(Fab *f, Reg chip[])
{
	Reg	*r;

	putln(f,"static UWORD\n"
		"custom_wget(CPTR addr)\n"
		"{\n"
		"	switch (addr & 0xffff) {\n");

	for (r = chip; r->name != NULL; r++) {
		if (r->w.get != 0) {
			putln(f,"	case %s:\n", r->name);
			f->lvl += 2;
			r->w.get(f, r);
			f->lvl -= 2;
		}
	}

	putln(f,"	default:\n"
		"		fatal();\n"
		"		return 0;\n"
		"	}\n"
		"}\n"
		"\n");
}

void
gen_wput(Fab *f, Reg chip[])
{
	Reg	*r;

	putln(f,"static void\n"
		"custom_wput(CPTR addr, UWORD value)\n"
		"{\n"
		"	switch (addr & 0xffff) {\n");

	for (r = chip; r->name != NULL; r++) {
		if (r->w.put != 0) {
			putln(f,"	case %s:\n", r->name);
			f->lvl += 2;
			r->w.put(f, r);
			f->lvl -= 2;
			putln(f,"		break;\n");
		}
	}

	putln(f,"	default:\n"
		"		fatal();\n"
		"		break;\n"
		"	}\n"
		"}\n"
		"\n");
}

void
gen_lget(Fab *f, Reg chip[])
{
	Reg	*r;

	putln(f,"static ULONG\n"
		"custom_lget(CPTR addr)\n"
		"{\n"
		"	switch (addr & 0xffff) {\n");

	for (r = chip; r->name != NULL; r++) {
		if (r->l.get != 0) {
			putln(f,"	case %s:\n", r->name);
			f->lvl += 2;
			r->l.get(f, r);
			f->lvl -= 2;
		}
	}

	putln(f,"	default:\n"
		"		fatal();\n"
		"		return 0;\n"
		"	}\n"
		"}\n"
		"\n");
}

void
gen_lput(Fab *f, Reg chip[])
{
	Reg	*r;

	putln(f,"static void\n"
		"custom_lput(CPTR addr, ULONG value)\n"
		"{\n"
		"	switch (addr & 0xffff) {\n");

	for (r = chip; r->name != NULL; r++) {
		if (r->l.put != 0) {
			putln(f,"	case %s:\n", r->name);
			f->lvl += 2;
			r->l.put(f, r);
			f->lvl -= 2;
			putln(f,"		break;\n");
		}
	}

	putln(f,"	default:\n"
		"		fatal();\n"
		"		break;\n"
		"	}\n"
		"}\n"
		"\n");
}

/*---------------------------------------------------------------------------*
 * XXX Most of this will go away as I figure out where the pieces belong
 *						Max Okumoto
 *---------------------------------------------------------------------------*/
static char	*HACK[] = {
"
/****************************************
 * 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;
}

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();
}

/*
 * 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) & 7;
			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;
}
"
};

/*---------------------------------------------------------------------------*
 * Hardware description
 *---------------------------------------------------------------------------*/
static Reg dragonball[] = {
	/* System Control */
	{"SCR",		0xF000, 1, 0x0c, /* System Control Reg */
		{reg_get, scr_put}, {0, 0}, {0, 0},
		"WDTH8:1;RSVD:1;DMAP:1;SO:1;BETEN:1;PRV:1;WPV:1;BETO:1;"},
#if NOT_IMPL
	{"MRR",		0xF004, 4, 0x00, /* Mask Revision Reg */
		{0, 0}, {0, 0}, {0, 0},
		""},
#endif

	/* Chip Select */
	{"GRPBASEA",	0xF100, 2, 0x0000, /* Chip Select Group A Base Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"V:1;:3;GMA:12;"},
#if NOT_IMPL
	{"GRPBASEB",	0xF102, 2, 0x0000, /* Chip Select Group B Base Reg */
		{0, 0}, {0, 0}, {0, 0},
		"V:1;:3;GMA:12;"},
#endif
	{"GRPBASEC",	0xF104, 2, 0x0000, /* Chip Select Group C Base Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"V:1;:3;GMA:12;"},
#if NOT_IMPL
	{"GRPBASED",	0xF106, 2, 0x0000, /* Chip Select Group D Base Reg */
		{0, 0}, {0, 0}, {0, 0},
		"V:1;:3;GMA:12;"},
#endif
	{"GRPMASKA",	0xF108, 2, 0x0000, /* Chip Select Group A Mask Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		":4;GMA:12;"},
#if NOT_IMPL
	{"GRPMASKB",	0xF10A, 2, 0x0000, /* Chip Select Group B Mask Reg */
		{0, 0}, {0, 0}, {0, 0},
		":4;GMA:12;"},
#endif
	{"GRPMASKC",	0xF10C, 2, 0x0000, /* Chip Select Group C Mask Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		":4;GMA:12;"},
#if NOT_IMPL
	{"GRPMASKD",	0xF10E, 2, 0x0000, /* Chip Select Group D Mask Reg */
		{0, 0}, {0, 0}, {0, 0},
		":4;GMA:12;"},
#endif
	{"CSA0",	0xF110, 4, 0x00010006, /* Group A Chip Select 0 Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSA1",	0xF114, 4, 0x00010006, /* Group A Chip Select 1 Reg */
		{0, 0}, {0, 0}, {reg_get, csa1_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSA2",	0xF118, 4, 0x00010006, /* Group A Chip Select 2 Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSA3",	0xF11C, 4, 0x00010006, /* Group A Chip Select 3 Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
#if NOT_IMPL
	{"CSB0",	0xF120, 4, 0x00010006, /* Group B Chip Select 0 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSB1",	0xF124, 4, 0x00010006, /* Group B Chip Select 1 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSB2",	0xF128, 4, 0x00010006, /* Group B Chip Select 2 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSB3",	0xF12C, 4, 0x00010006, /* Group B Chip Select 3 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
#endif
	{"CSC0",	0xF130, 4, 0x00010006, /* Group C Chip Select 0 Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSC1",	0xF134, 4, 0x00010006, /* Group C Chip Select 1 Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSC2",	0xF138, 4, 0x00010006, /* Group C Chip Select 2 Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSC3",	0xF13C, 4, 0x00010006, /* Group C Chip Select 3 Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
#if NOT_IMPL
	{"CSD0",	0xF140, 4, 0x00010006, /* Group D Chip Select 0 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSD1",	0xF144, 4, 0x00010006, /* Group D Chip Select 1 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSD2",	0xF148, 4, 0x00010006, /* Group D Chip Select 2 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
	{"CSD3",	0xF14C, 4, 0x00010006, /* Group D Chip Select 3 Reg */
		{0, 0}, {0, 0}, {0, 0},
		"WAIT:3;RO:1;:4;AM:8;BSW:1;:7;AC:8;"},
#endif

	/* Phase Locked Loop */
	{"PLLCR",	0xF200, 2, 0x2400, /* PLL Control Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		":3;DISPLL:1;CLKEN:1;:3;SYSCLKSEL:3;PIXCLKSEL:3;:2;"},
	{"PLLFSR",	0xF202, 2, 0x0123, /* PLL Frequency Select Reg */
		{0, 0}, {pllfsr_get, reg_put}, {0, 0},
		"PC:8;QC:4;:2;PROT:1;CLK32:1;"},
	{"PCTLR",	0xF207, 1, 0x1f, /* Power Control Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"WIDTH:5;:1;STOP:1;PCEN:1;"},

	/* Interrupt controller */
	{"IVR",		0xF300, 1, 0x00, /* Interrupt Vector Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"LEVEL:3;VECTOR:5;"},
	{"ICR",		0xF302, 2, 0x0000, /* Interrupt Control Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		":8;POL6:1;POL3:1;POL2:1;POL1:1;ET6:1;ET3:1;ET2:1;ET1:1;"},
	{"IMR",		0xF304, 4, 0x00ffffff, /* Interrupt Mask Reg */
		{0, 0}, {imr_get_xxx, imr_put_xxx}, {reg_get, imr_put},
		"SPIM:1;TMR2:1;UART:1;WDT:1;RTC:1;LCDC:1;KB:1;PWM:1;INT0:1;INT1:1;INT2:1;INT3:1;INT4:1;INT5:1;INT6:1;INT7:1;IRQ1:1;IRQ2:1;IRQ3:1;IRQ6:1;PEN:1;SPIS:1;TMR1:1;IRQ7:1;:8;"},
	{"IWR",		0xF308, 4, 0x00ffffff, /* Interrupt Wakeup Enable Reg */
		{0, 0}, {iwr_get_xxx, iwr_put_xxx}, {reg_get, reg_put},
		"SPIM:1;TMR2:1;UART:1;WDT:1;RTC:1;LCDC:1;KB:1;PWM:1;INT0:1;INT1:1;INT2:1;INT3:1;INT4:1;INT5:1;INT6:1;INT7:1;IRQ1:1;IRQ2:1;IRQ3:1;IRQ6:1;PEN:1;SPIS:1;TMR1:1;IRQ7:1;:8;"},
	{"ISR",		0xF30C, 4, 0x00000000, /* Interrupt Status Reg */
		{0, 0}, {isr_get_xxx, isr_put_xxx}, {reg_get, isr_put},
		"SPIM:1;TMR2:1;UART:1;WDT:1;RTC:1;LCDC:1;KB:1;PWM:1;INT0:1;INT1:1;INT2:1;INT3:1;INT4:1;INT5:1;INT6:1;INT7:1;IRQ1:1;IRQ2:1;IRQ3:1;IRQ6:1;PEN:1;SPIS:1;TMR1:1;IRQ7:1;:8;"},
	{"IPR",		0xF310, 4, 0x00000000, /* Interrupt Pending Reg */
		{0, 0}, {ipr_get_xxx, 0}, {ipr_get, ipr_put},
		"SPIM:1;TMR2:1;UART:1;WDT:1;RTC:1;LCDC:1;KB:1;PWM:1;INT0:1;INT1:1;INT2:1;INT3:1;INT4:1;INT5:1;INT6:1;INT7:1;IRQ1:1;IRQ2:1;IRQ3:1;IRQ6:1;PEN:1;SPIS:1;TMR1:1;IRQ7:1;:8;"},

	/* Parallel IO */
#if NOT_IMPL
	{"PADIR",	0xF400, 1, 0x00, /* Port A Direction Reg */
		{0, 0}, {0, 0}, {0, 0},
		""},
	{"PADATA",	0xF401, 1, 0x00, /* Port A Data Reg */
		{0, 0}, {0, 0}, {0, 0},
		""},
	{"PASEL",	0xF403, 1, 0x00, /* Port A Select Reg */
		{0, 0}, {0, 0}, {0, 0},
		""},

	{"PBDIR",	0xF408, 1, 0x00, /* Port B Direction Reg */
		{0, 0}, {0, 0}, {0, 0},
		""},
	{"PBDATA",	0xF409, 1, 0x00, /* Port B Data Reg */
		{0, 0}, {0, 0}, {0, 0},
		""},
	{"PBSEL",	0xF40B, 1, 0x00, /* Port B Select Reg */
		{0, 0}, {0, 0}, {0, 0},
		""},
#endif
	{"PCDIR",	0xF410, 1, 0x00, /* Port C Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"MOCLK:1;UDS:1;LDS:1;:1;NMI:1;DTACK:1;WE:1;:1;"},
	{"PCDATA",	0xF411, 1, 0x00, /* Port C Data Reg */
		{pcdata_get, reg_put}, {0, 0}, {0, 0},
		"MOCLK:1;UDS:1;LDS:1;:1;NMI:1;DTACK:1;WE:1;:1;"},
	{"PCSEL",	0xF413, 1, 0x00, /* Port C Select Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"MOCLK:1;UDS:1;LDS:1;:1;NMI:1;DTACK:1;WE:1;:1;"},

	{"PDDIR",	0xF418, 1, 0x00, /* Port D Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"BB0:1;B1:1;B2:1;B3:1;B4:1;B5:1;B6:1;B7:1;"},
	{"PDDATA",	0xF419, 1, 0x00, /* Port D Data Reg */
		{reg_get, pddata_put}, {0, 0}, {0, 0},
		"BB0:1;B1:1;B2:1;B3:1;B4:1;B5:1;B6:1;B7:1;"},
	{"PDPUEN",	0xF41A, 1, 0xff, /* Port D Pullup Enable Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"BB0:1;B1:1;B2:1;B3:1;B4:1;B5:1;B6:1;B7:1;"},
	{"PDPOL",	0xF41C, 1, 0x00, /* Port D Polarity Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"BB0:1;B1:1;B2:1;B3:1;B4:1;B5:1;B6:1;B7:1;"},
	{"PDIRQEN",	0xF41D, 1, 0x00, /* Port D IRQ Enable Reg */
		{reg_get, pdirqen_put}, {0, 0}, {0, 0},
		"BB0:1;B1:1;B2:1;B3:1;B4:1;B5:1;B6:1;B7:1;"},
	{"PDIRQEDGE",	0xF41F, 1, 0x00, /* Port D IRQ Edge Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"BB0:1;B1:1;B2:1;B3:1;B4:1;B5:1;B6:1;B7:1;"},

	{"PEDIR",	0xF420, 1, 0x00, /* Port E Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PEDATA",	0xF421, 1, 0x00, /* Port E Data Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PEPUEN",	0xF422, 1, 0x80, /* X Port E Pullup Enable Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PESEL",	0xF423, 1, 0x80, /* X Port E Select Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},

	{"PFDIR",	0xF428, 1, 0x00, /* Port F Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PFDATA",	0xF429, 1, 0x00, /* Port F Data Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PFPUEN",	0xF42A, 1, 0xff, /* Port F Pullup Enable Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PFSEL",	0xF42B, 1, 0xff, /* Port F Select Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},

	{"PGDIR",	0xF430, 1, 0x00, /* Port G Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"UART_TXD:1;UART_RXD:1;PWMOUT:1;TOUT2:1;TIN2:1;TOUT1:1;TIN1:1;RTCOUT:1;"},
	{"PGDATA",	0xF431, 1, 0x00, /* Port G Data Reg */
		{reg_get, pgdata_put}, {0, 0}, {0, 0},
		"UART_TXD:1;UART_RXD:1;PWMOUT:1;TOUT2:1;TIN2:1;TOUT1:1;TIN1:1;RTCOUT:1;"},
	{"PGPUEN",	0xF432, 1, 0xff, /* Port G Pullup Enable Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"UART_TXD:1;UART_RXD:1;PWMOUT:1;TOUT2:1;TIN2:1;TOUT1:1;TIN1:1;RTCOUT:1;"},
	{"PGSEL",	0xF433, 1, 0xff, /* Port G Select Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"UART_TXD:1;UART_RXD:1;PWMOUT:1;TOUT2:1;TIN2:1;TOUT1:1;TIN1:1;RTCOUT:1;"},

	{"PJDIR",	0xF438, 1, 0x00, /* Port J Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PJDATA",	0xF439, 1, 0x00, /* Port J Data Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},
	{"PJSEL",	0xF43B, 1, 0x00, /* Port J Select Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"A:8;"},

	{"PKDIR",	0xF440, 1, 0x00, /* Port K Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"SPIM_TXD:1;SPIM_RXD:1;SPIM_CLKO:1;SPIS_EN:1;SPIS_RXD:1;SPIS_CLKI:1;PCMCIA_CE2:1;PCMCIA_CE1:1;"},
	{"PKDATA",	0xF441, 1, 0x00, /* Port K Data Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"SPIM_TXD:1;SPIM_RXD:1;SPIM_CLKO:1;SPIS_EN:1;SPIS_RXD:1;SPIS_CLKI:1;PCMCIA_CE2:1;PCMCIA_CE1:1;"},
	{"PKPUEN",	0xF442, 1, 0x3f, /* Port K Pullup Enable Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"SPIM_TXD:1;SPIM_RXD:1;SPIM_CLKO:1;SPIS_EN:1;SPIS_RXD:1;SPIS_CLKI:1;PCMCIA_CE2:1;PCMCIA_CE1:1;"},
	{"PKSEL",	0xF443, 1, 0x3f, /* Port K Select Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"SPIM_TXD:1;SPIM_RXD:1;SPIM_CLKO:1;SPIS_EN:1;SPIS_RXD:1;SPIS_CLKI:1;PCMCIA_CE2:1;PCMCIA_CE1:1;"},

	{"PMDIR",	0xF448, 1, 0x00, /* Port M Direction Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"CTS:1;RTS:1;IRQ6:1;IRQ3:1;IRQ2:1;IRQ1:1;PEN_IRQ:1;UART_GPIO:1;"},
	{"PMDATA",	0xF449, 1, 0x00, /* Port M Data Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"CTS:1;RTS:1;IRQ6:1;IRQ3:1;IRQ2:1;IRQ1:1;PEN_IRQ:1;UART_GPIO:1;"},
	{"PMPUEN",	0xF44A, 1, 0xff, /* Port M Pullup Enable Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"CTS:1;RTS:1;IRQ6:1;IRQ3:1;IRQ2:1;IRQ1:1;PEN_IRQ:1;UART_GPIO:1;"},
	{"PMSEL",	0xF44B, 1, 0x02, /* Port M Select Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"CTS:1;RTS:1;IRQ6:1;IRQ3:1;IRQ2:1;IRQ1:1;PEN_IRQ:1;UART_GPIO:1;"},

	/* Pulse Width Modulator */
	{"PWMC",	0xF500, 2, 0x0000, /* PWM Control Reg */
		{pwmc_get_xxx, pwmc_put_xxx}, {reg_get, reg_put}, {0, 0},
		"CLKSEL:3;:1;PWMEN:1;POL:1;:1;PIN:1;LOAD:1;:5;IRQEN:1;PWMIRQ:1;"},
	{"PWMP",	0xF502, 2, 0x0000, /* PWM Period Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"PERIOD:16;"},
	{"PWMW",	0xF504, 2, 0x0000, /* PWM Width Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"WIDTH:16;"},
#if NOT_IMPL
	{"PWMCNT",	0xF506, 2, 0x0000, /* PWM Counter Reg */
		{0, 0}, {0, 0}, {0, 0},
		"COUNT:16;"},
#endif

	/* Timer */
	{"TCTL1",	0xF600, 2, 0x0000, /* Timer Unit 1 Control Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"TEN:1;CLKSOURCE:3;IRQEN:1;OM:1;CAPTURE_EDGE:2;FRR:1;:7;"},
	{"TPRER1",	0xF602, 2, 0x0000, /* Timer Unit 1 Prescaler Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"PRESCALE:8;:8;"},
	{"TCMP1",	0xF604, 2, 0xffff, /* Timer Unit 1 Compare Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"COMPARE:16;"},
#if NOT_IMPL
	{"TCR1",	0xF606, 2, 0x0000, /* Timer Unit 1 Capture Reg */
		{0, 0}, {0, 0}, {0, 0},
		"CAPTURE:16;"},
#endif
	{"TCN1",	0xF608, 2, 0x0000, /* Timer Unit 1 Counter Reg */
		{0, 0}, {0, 0}, {0, 0},
		"COUNT:16;"},
	{"TSTAT1",	0xF60A, 2, 0x0000, /* Timer Unit 1 Status Reg */
		{0, 0}, {tstat1_get, tstat1_put}, {0, 0},
		"COMP:1;CAPT:1;:14;"},
	{"TCTL2",	0xF60C, 2, 0x0000, /* Timer Unit 2 Control Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"TEN:1;CLKSOURCE:3;IRQEN:1;OM:1;CAPTURE_EDGE:2;FRR:1;:7;"},
	{"TPRER2",	0xF60E, 2, 0x0000, /* Timer Unit 2 Prescaler Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"PRESCALE:8;:8;"},
	{"TCMP2",	0xF610, 2, 0xffff, /* Timer Unit 2 Compare Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"COMPARE:16;"},
#if NOT_IMPL
	{"TCR2",	0xF612, 2, 0x0000, /* Timer Unit 1 Capture Reg */
		{0, 0}, {0, 0}, {0, 0},
		"CAPTURE:16;"},
#endif
	{"TCN2",	0xF614, 2, 0x0000, /* Timer Unit 2 Counter */
		{0, 0}, {0, 0}, {0, 0},
		"COUNT:16;"},
	{"TSTAT2",	0xF616, 2, 0x0000, /* Timer Unit 2 Status Reg */
		{0, 0}, {tstat2_get, tstat2_put}, {0, 0},
		"COMP:1;CAPT:1;:14;"},

	/* Watchdog */
	{"WCSR",	0xF618, 2, 0x0001, /* Watchdog Control and Status Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"WDEN:1;FI:1;LOCK:1;WDRST:1;:12;"},
#if NOT_IMPL
	{"WRR",		0xF61A, 2, 0xffff, /* Watchdog Compare Reg */
		{0, 0}, {0, 0}, {0, 0},
		"COMPARE:16;"},
#endif
	{"WCN",		0xF61C, 2, 0x0000, /* Watchdog Counter */
		{0, 0}, {reg_get, wcn_put}, {0, 0},
		"COUNT:16;"},

	/* Serial Peripheral Interface Slave */
#if NOT_IMPL
	{"SPISR",	0xF700, 2, 0x0000, /* SPIS Reg */
		{0, 0}, {0, 0}, {0, 0},
		"DATA:8;SPIS_EN:1;POL:1;PHA:1;OVWR:1;DATA_RDY:1;EN_POL:1;IRQEN:1;SPISIRQ:1;"},
#endif

	/* Serial Peripheral Interface Master */
	{"SPIMDATA",	0xF800, 2, 0x0000, /* SPIM Data Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"DATA:16;"},
	{"SPIMCONT",	0xF802, 2, 0x0000, /* SPIM Control/Status Reg */
		{0, 0}, {reg_get, spimcont_put}, {0, 0},
		"BITCOUNT:4;POL:1;PHA:1;IRQEN:1;SPIMIRQ:1;XCH:1;SPMEN:1;:3;DATARATE:3;"},

	/* UART - Universal Asynchronous Receiver/Transmitter */
	{"USTCNT",	0xF900, 2, 0x0000, /* UART Status/Control Reg */
		{0, 0}, {reg_get, ustcnt_put}, {0, 0},
		"TX_AVAIL_ENABLE:1;TX_HALF_ENABLE:1;TX_EMPTY_ENABLE:1;RX_READY_ENABLE:1;RX_HALF_ENABLE:1;RX_FULL_ENABLE:1;CTS_DELTA_ENABLE:1;GPIO_DELTA_ENABLE:1;BITS_8:1;STOP_BITS:1;ODD_EVEN:1;PARITY_ENABLE:1;RX_CLK_CONT:1;TX_ENABLE:1;RX_ENABLE:1;UART_ENABLE:1;"},
	{"UBAUD",	0xF902, 2, 0x003f, /* UART Baud Control Reg */
		{0, 0}, {reg_get, ubaud_put}, {0, 0},
		"PRESCALER:6;:2;DIVIDE:3;BAUD_SRC:1;GPIO_SRC:1;GPIO_DIR:1;GPIO:1;GPIO_DELTA:1;"},
	{"URX",		0xF904, 2, 0x0000, /* UART RX Reg */
		{urx_get_xxx, 0}, {urx_get, urx_put}, {0, 0},
		"DATA:8;PARITY_ERROR:1;BREAK:1;FRAME_ERROR:1;OVRUN:1;:1;DATA_READY:1;FIFO_HALF:1;FIFO_FULL:1;"},
	{"UTX",		0xF906, 2, 0x0000, /* UART TX Reg */
		{0, utx_put_xxx}, {utx_get, utx_put}, {0, 0},
		"DATA:8;CTS_DELTA:1;CTS_STATUS:1;:1;IGNORE_CTS:1;SEND_BREAK:1;TX_AVAIL:1;FIFO_HALF:1;FIFO_EMPTY:1;"},
	{"UMISC",	0xF908, 2, 0x0000, /* UART Misc Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		":2;TX_POL:1;RX_POL:1;IRDA_LOOP:1;IRDA_ENABLE:1;RTS:1;RTS_CONT:1;:4;LOOP:1;FORCE_PERR:1;CLK_SRC:1;:1;"},

	/* LCD Controller */
	{"LSSA",	0xFA00, 4, 0x00000000, /* Screen Starting Address Reg */
		{0, 0}, {0, 0}, {reg_get, lssa_put},
		"SSA:32;"},
	{"LVPW",	0xFA05, 1, 0xff, /* Virtual Page Width Reg */
		{reg_get, lvpw_put}, {0, 0}, {0, 0},
		"VPW:8;"},
	{"LXMAX",	0xFA08, 2, 0x03ff, /* Screen Width Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"XMAX:10;:6;"},
	{"LYMAX",	0xFA0A, 2, 0x01ff, /* Screen Height Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"YMAX:10;:6;"},
	{"LCXP",	0xFA18, 2, 0x0000, /* Cursor X Position */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"CXP:10;:4;CC:2;"},
	{"LCYP",	0xFA1A, 2, 0x0000, /* Cursor Y Position */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"CYP:10;:6;"},
	{"LCWCH",	0xFA1C, 2, 0x0101, /* Cursor Width & Height Reg */
		{0, 0}, {reg_get, reg_put}, {0, 0},
		"CH:5;:3;CW:5;:3;"},
	{"LBLKC",	0xFA1F, 1, 0x7f, /* Blink Control Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"BD:7;BKEN:1;"},
	{"LPICF",	0xFA20, 1, 0x00, /* Panel Interface Config Reg */
		{reg_get, lpicf_put}, {0, 0}, {0, 0},
		"GS:1;PBSIZ:2;:5;"},
#if NOT_IMPL
	{"LPOLCF",	0xFA21, 1, 0x00, /* Polarity Config Reg */
		{0, 0}, {0, 0}, {0, 0},
		"PIXPOL:1;LPPOL:1;FLMPOL:1;LCKPOL:1;:4;"},
	{"LACDRC",	0xFA23, 1, 0x00, /* ACD (M) Rate Control Reg */
		{0, 0}, {0, 0}, {0, 0},
		"ACD:4;:4;"},
#endif
	{"LPXCD",	0xFA25, 1, 0x00, /* Pixel Clock Divider Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"PCD:6;:2;"},
	{"LCKCON",	0xFA27, 1, 0x40, /* Clocking Control Reg */
		{reg_get, lckcon_put}, {0, 0}, {0, 0},
		"PCDS:1;DWIDTH:1;WS:4;DMA16:1;LCDCON:1;"},
	{"LLBAR",	0xFA29, 1, 0x3e, /* Last Buffer Address Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"LBAR:7;:1;"},
	{"LOTCR",	0xFA2B, 1, 0x3f, /* Octet Terminal Count Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"OTC:8;"},
	{"LPOSR",	0xFA2D, 1, 0x00, /* Panning Offset Reg */
		{reg_get, lposr_put}, {0, 0}, {0, 0},
		"POS:3;BOS:1;:4;"},
	{"LFRCM",	0xFA31, 1, 0xb9, /* Frame Rate Control Modulation Reg */
		{reg_get, reg_put}, {0, 0}, {0, 0},
		"YMOD:4;XMOD:4;"},
	{"LGPMR",	0xFA32, 2, 0x1073, /* Gray Palette Mapping Reg */
		{0, 0}, {reg_get, lgpmr_put}, {0, 0},
		"G2:4;G3:4;G0:4;G1:4;"},

	/* Real Time Clock */
	{"RTCHMS",	0xFB00, 4, 0x00000000, /* Hours Minutes Seconds Reg */
		{0, 0}, {0, 0}, {rhmsr_get, reg_put},
		"SECONDS:6;:10;MINUTES:6;:2;HOURS:5;:3;"},
	{"RTCALARM",	0xFB04, 4, 0x00000000, /* Alarm Reg */
		{0, 0}, {0, 0}, {reg_get, reg_put},
		"SECONDS:6;:10;MINUTES:6;:2;HOURS:5;:3;"},
	{"RTCCTL",	0xFB0C, 1, 0x00, /* Control Reg */
		{reg_get, reg_put}, {reg_get, rctl_put_xxx}, {0, 0},
		":5;REF384:1;:1;ENABLE:1;"},
	{"RTCISR",	0xFB0E, 1, 0x00, /* Interrupt Status Reg */
		{reg_get, risr_put}, {reg_get, risr_put_xxx}, {0, 0},
		"SW:1;MININT:1;ALARM:1;HOUR24:1;HZ1:1;:3;"},
	{"RTCIENR",	0xFB10, 1, 0x00, /* Interrupt Enable Reg */
		{reg_get, reg_put}, {reg_get, rienr_put_xxx}, {0, 0},
		"SW:1;MININT:1;ALARM:1;HOUR24:1;HZ1:1;:3;"},
#if NOT_IMPL
	{"STPWCH",	0xFB12, 1, 0x00, /* Interrupt Enable Reg */
		{0, 0}, {0, 0}, {0, 0},
		"COUNT:8;:8;"},
#endif

	{NULL}
};

/*---------------------------------------------------------------------------*
 * Main function
 *---------------------------------------------------------------------------*/

int
main(int argc, char *argv[])
{
	Fab	fab;

#ifdef WORDS_BIGENDIAN
	fab.bo = FAB_BIGENDIAN;
#else
	fab.bo = FAB_LITTLEENDIAN;
#endif
	fab.f_c = fopen("custom.c", "w");
	fab.lvl = 0;

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

	putln(&fab,
		"#include <ctype.h>\n"
		"#include <assert.h>\n"
		"#include <stdio.h>\n"
		"#include <time.h>\n"
		"#include <sys/types.h>\n"
		"#include <sys/time.h>\n"
		"#include <unistd.h>\n"
		"\n"
		"#include \"config.h\"\n"
		"#include \"sysdeps.h\"\n"
		"#include \"shared.h\"\n"
		"#include \"memory.h\"\n"
		"#include \"custom.h\"\n"
		"#include \"newcpu.h\"\n"
		"\n"
		"extern int sram_protect;\n"
		"\n");

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

	putln(&fab,
		"/* dragonball register definitions */\n"
		"\n");
	gen_vars(&fab, dragonball);
	putln(&fab,
		"static shared_img *CustShptr = 0;\n"
		"\n"
		"static union {\n"
		"	UWORD	x;\n"
		"	struct {\n"
		"#ifdef WORDS_BIGENDIAN\n"
		"		unsigned FIFO_FULL	:1;\n"
		"		unsigned FIFO_HALF	:1;\n"
		"		unsigned DATA_READY	:1;\n"
		"		unsigned unused		:1;\n"
		"		unsigned OVRUN		:1;\n"
		"		unsigned FRAME_ERROR	:1;\n"
		"		unsigned BREAK		:1;\n"
		"		unsigned PARITY_ERROR	:1;\n"
		"		unsigned DATA		:8;\n"
		"#else /* not WORDS_BIGENDIAN */\n"
		"		unsigned DATA		:8;\n"
		"		unsigned PARITY_ERROR	:1;\n"
		"		unsigned BREAK		:1;\n"
		"		unsigned FRAME_ERROR	:1;\n"
		"		unsigned OVRUN		:1;\n"
		"		unsigned unused		:1;\n"
		"		unsigned DATA_READY	:1;\n"
		"		unsigned FIFO_HALF	:1;\n"
		"		unsigned FIFO_FULL	:1;\n"
		"#endif /* not WORDS_BIGENDIAN */\n"
		"	} anon;\n"
		"} db_URXdb;\n"
		"static UWORD	db_TSTAT1_lastseen;\n"
		"static UWORD	db_TSTAT2_lastseen;\n"
		"static UBYTE	db_PDDATA_edge;\n"
		"\n"
		"static unsigned long cycles;\n"
		"\n"
		"static int pendown = 0;\n"
		"static int penx;\n"
		"static int peny;\n"
		"\n"
		"/*\n"
		" * Exported variable\n"
		" */\n"
		"unsigned long specialflags;\n"
		"\n"
	);

	gen_init(&fab, dragonball);
	putln(&fab,
		"void\n"
		"customreset(void)\n"
		"{\n"
		"	cycles = 0;\n"
		"	specialflags = 0;\n"
		"\n"
		"	db_TSTAT1_lastseen = 0x0000;\n"
		"	db_TSTAT2_lastseen = 0x0000;\n"
		"	db_PDDATA_edge = 0x00;\n"
		"\n"
		"	db_URXdb.x = 0x0000;\n"
		"\n"
		"	db_reset();\n"
		"}\n"
		"\n");


	putln(&fab, HACK[0]);
	putln(&fab, "\n");

	gen_lget(&fab, dragonball);
	gen_lput(&fab, dragonball);
	gen_wget(&fab, dragonball);
	gen_wput(&fab, dragonball);
	gen_bget(&fab, dragonball);
	gen_bput(&fab, dragonball);

	putln(&fab,
		"addrbank custom_bank = {\n"
		"	custom_lget, custom_wget, custom_bget,\n"
		"	custom_lput, custom_wput, custom_bput,\n"
		"	default_xlate, default_check\n"
		"};\n"
		"\n");

	fclose(fab.f_c);
	return(0);
}

