/*
 * Copyright (C) 2007-2017 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

/*
 * Memory hierarchy:
 *
 * cpu/fpu (align)
 * seg
 * cache1i/cache1d
 * mmui/mmud/mtrr
 * a20gate
 * cache2
 * apic
 * bus
 */

#define DEBUG_BIOS_POST_CODE	0

#define XCONC(a, b, c)	a ## _ ## b ## _ ## c
#define CONC(a, b, c)	XCONC(a, b, c)
#include "exec-all.h"

#include "config.h"
#include "compiler.h"

#include <assert.h>
#include "fixme.h"
#include <fenv.h>
#include <inttypes.h>
#include <math.h>
#include <setjmp.h>
#include <stdio.h>
#include <string.h>

#include "system.h"
#include "glue-main.h"
#include "glue-shm.h"
#include "glue-suspend.h"
#include "glue-lru.h"
#include "glue-floatx.h"

#include "arch_gen_cpu_x86_state.h"

#define EXPORT

#define NAME		apic
#define NAME_(x)	CONC(CHIP, apic, x)
#include "arch_gen_cpu_x86_apic.c"
#undef NAME_
#undef NAME

#if defined CONFIG_CPU_L2_SIZE
#define CONFIG_CACHE2_ASSOC	CONFIG_CPU_L2_ASSOC
#define CONFIG_CACHE2_SIZE	CONFIG_CPU_L2_SIZE
#define CONFIG_CACHE2_LINE_SIZE	CONFIG_CPU_CACHE_LINE_SIZE
#endif
#define NAME		cache2
#define NAME_(x)	CONC(CHIP, cache2, x)
#include "arch_gen_cpu_x86_cache2.c"
#undef NAME_
#undef NAME
#if defined CONFIG_CPU_L2_SIZE
#undef CONFIG_CACHE2_LINE_SIZE
#undef CONFIG_CACHE2_SIZE
#undef CONFIG_CACHE2_ASSOC
#endif

#define NAME		mtrr
#define NAME_(x)	CONC(CHIP, mtrr, x)
#include "arch_gen_cpu_x86_mtrr.c"
#undef NAME_
#undef NAME

#define NAME		a20gate
#define NAME_(x)	CONC(CHIP, a20gate, x)
#include "arch_gen_cpu_x86_a20gate.c"
#undef NAME_
#undef NAME

#define NAME		mmui
#define NAME_(x)	CONC(CHIP, mmui, x)
#ifdef CONFIG_CPU_TLBI_SIZE
#define CONFIG_MMU_TLB_ASSOC	CONFIG_CPU_TLBI_ASSOC
#define CONFIG_MMU_TLB_SIZE	CONFIG_CPU_TLBI_SIZE
#elif defined CONFIG_CPU_TLBI4M_SIZE && defined CONFIG_CPU_TLBI4K_SIZE
#define CONFIG_MMU_TLB4K_ASSOC	CONFIG_CPU_TLBI4K_ASSOC
#define CONFIG_MMU_TLB4K_SIZE	CONFIG_CPU_TLBI4K_SIZE
#define CONFIG_MMU_TLB4M_ASSOC	CONFIG_CPU_TLBI4M_ASSOC
#define CONFIG_MMU_TLB4M_SIZE	CONFIG_CPU_TLBI4M_SIZE
#endif
#include "arch_gen_cpu_x86_mmu.c"
#undef CONFIG_MMU_TLB4M_SIZE
#undef CONFIG_MMU_TLB4M_ASSOC
#undef CONFIG_MMU_TLB4K_SIZE
#undef CONFIG_MMU_TLB4K_ASSOC
#undef CONFIG_MMU_TLB_SIZE
#undef CONFIG_MMU_TLB_ASSOC
#undef NAME_
#undef NAME

#define NAME		mmud
#define NAME_(x)	CONC(CHIP, mmud, x)
#ifdef CONFIG_CPU_TLBD_SIZE
#define CONFIG_MMU_TLB_ASSOC	CONFIG_CPU_TLBD_ASSOC
#define CONFIG_MMU_TLB_SIZE	CONFIG_CPU_TLBD_SIZE
#elif defined CONFIG_CPU_TLBD4M_SIZE && defined CONFIG_CPU_TLBD4K_SIZE
#define CONFIG_MMU_TLB4K_ASSOC	CONFIG_CPU_TLBD4K_ASSOC
#define CONFIG_MMU_TLB4K_SIZE	CONFIG_CPU_TLBD4K_SIZE
#define CONFIG_MMU_TLB4M_ASSOC	CONFIG_CPU_TLBD4M_ASSOC
#define CONFIG_MMU_TLB4M_SIZE	CONFIG_CPU_TLBD4M_SIZE
#endif
#include "arch_gen_cpu_x86_mmu.c"
#undef CONFIG_MMU_TLB4M_SIZE
#undef CONFIG_MMU_TLB4M_ASSOC
#undef CONFIG_MMU_TLB4K_SIZE
#undef CONFIG_MMU_TLB4K_ASSOC
#undef CONFIG_MMU_TLB_SIZE
#undef CONFIG_MMU_TLB_ASSOC
#undef NAME_
#undef NAME

#define NAME		cache1i
#define NAME_(x)	CONC(CHIP, cache1i, x)
#define CONFIG_CODE
#ifdef CONFIG_CPU_L1I_SIZE
#define CONFIG_SIZE	CONFIG_CPU_L1I_SIZE
#define CONFIG_ASSOC	CONFIG_CPU_L1I_ASSOC
#endif
#include "arch_gen_cpu_x86_cache1.c"
#ifdef CONFIG_CPU_L1I_SIZE
#undef CONFIG_ASSOC
#undef CONFIG_SIZE
#endif
#undef CONFIG_CODE
#undef NAME_
#undef NAME

#define NAME		cache1d
#define NAME_(x)	CONC(CHIP, cache1d, x)
#define CONFIG_DATA
#ifdef CONFIG_CPU_L1D_SIZE
#define CONFIG_SIZE	CONFIG_CPU_L1D_SIZE
#define CONFIG_ASSOC	CONFIG_CPU_L1D_ASSOC
#endif
#include "arch_gen_cpu_x86_cache1.c"
#ifdef CONFIG_CPU_L1D_SIZE
#undef CONFIG_ASSOC
#undef CONFIG_SIZE
#endif
#undef CONFIG_DATA
#undef NAME_
#undef NAME

#define NAME		align
#define NAME_(x)	CONC(CHIP, align, x)
#include "arch_gen_cpu_x86_align_io.c"
#undef NAME_
#undef NAME

#define NAME		align
#define NAME_(x)	CONC(CHIP, align, x)
#include "arch_gen_cpu_x86_align.c"
#undef NAME_
#undef NAME

#define NAME		CHIP /* FIXME */
#define NAME_(x)	CHIP_(x) /* FIXME */
#include "arch_gen_cpu_x86_fpu.c"
#include "arch_gen_cpu_x86_core.c"
#include "cpu_jit_buffer.c"
#include "cpu_jit_compile.c"
#undef NAME_
#undef NAME

#undef EXPORT

#include "arch_gen_cpu_x86_align.h"
#include "arch_gen_cpu_x86_fpu.h"
#include "arch_gen_cpu_x86_core.h"

/*
 * Bus Interface
 */
static void
CHIP_(ior)(struct cpssp *cpssp, paddr_t port, unsigned int bs, udata_t *valp)
{
#if defined CONFIG_FPU && CONFIG_FPU
	if ((port >> 31) & 1) {
#if defined CONFIG_CPU_SOCKET_ISA
		assert(0); /* Mustn't happen. */

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
		fpu_read(cpssp, port, valp);

#elif defined CONFIG_CPU_SOCKET_HOST775
		uint32_t val;

		fpu_read(cpssp, port, &val);

		*valp = (udata_t) val;
#else
#error "Unknown socket."
#endif
	} else
#endif
	{
#if defined CONFIG_CPU_SOCKET_ISA
		uint8_t val8;

		switch (bs) {
		case 0x1:
			sig_isa_bus_inb(cpssp->port_bus, cpssp, &val8, port + 0);
			*valp = val8 << 0;
			break;
		case 0x2:
			sig_isa_bus_inb(cpssp->port_bus, cpssp, &val8, port + 1);
			*valp = val8 << 8;
			break;
		case 0x3:
			sig_isa_bus_inw(cpssp->port_bus, cpssp, valp, port + 0);
			break;
		}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
		*valp = (udata_t) (data_t) -1;
		if (unlikely(sig_host_bus_ior(cpssp->port_bus, cpssp, port, bs, valp) != 0)) {
			sig_host_bus_addr_type(cpssp->port_bus, cpssp, 0, port, SIG_HOST_BUS_IOR);
			/* delay... */
			sig_host_bus_read_data(cpssp->port_bus, cpssp, bs, valp);
		}

#elif defined CONFIG_CPU_SOCKET_HOST775
		*valp = (udata_t) (data_t) -1;
		if (unlikely(sig_host775_bus_ior(cpssp->port_bus, cpssp, port, bs, valp) != 0)) {
			sig_host775_bus_addr_type(cpssp->port_bus, cpssp, 0, port, SIG_HOST775_BUS_IOR);
			/* delay... */
			sig_host775_bus_read_data(cpssp->port_bus, cpssp, bs, valp);
		}

#else
#error "Unknown socket."
#endif
	}
}

static void
CHIP_(iow)(struct cpssp *cpssp, paddr_t port, unsigned int bs, udata_t val)
{
#if defined CONFIG_FPU && CONFIG_FPU
	if ((port >> 31) & 1) {
#if defined CONFIG_CPU_SOCKET_ISA
		assert(0); /* Mustn't happen. */

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
		fpu_write(cpssp, port, val);

#elif defined CONFIG_CPU_SOCKET_HOST775
		fpu_write(cpssp, port, (uint32_t) val);

#else
#error "Unknown socket."
#endif
	} else
#endif
	{
#if defined CONFIG_CPU_SOCKET_ISA
		switch (bs) {
		case 0x1:
			sig_isa_bus_outb(cpssp->port_bus, cpssp, val >> 0, port + 0);
			break;
		case 0x2:
			sig_isa_bus_outb(cpssp->port_bus, cpssp, val >> 8, port + 1);
			break;
		case 0x3:
			sig_isa_bus_outw(cpssp->port_bus, cpssp, val, port + 0);
			break;
		}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
		if (unlikely(sig_host_bus_iow(cpssp->port_bus, cpssp, port, bs, val) != 0)) {
			sig_host_bus_addr_type(cpssp->port_bus, cpssp, 0, port, SIG_HOST_BUS_IOW);
			/* delay... */
			sig_host_bus_write_data(cpssp->port_bus, cpssp, bs, val);
		}

#elif defined CONFIG_CPU_SOCKET_HOST775
		if (unlikely(sig_host775_bus_iow(cpssp->port_bus, cpssp, port, bs, val) != 0)) {
			sig_host775_bus_addr_type(cpssp->port_bus, cpssp, 0, port, SIG_HOST775_BUS_IOW);
			/* delay... */
			sig_host775_bus_write_data(cpssp->port_bus, cpssp, bs, val);
		}

#else
#error "Unknown socket."
#endif
	}
}

static int
CHIP_(mx)(void *_cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	struct cpssp *cpssp = _cpssp;

#if defined CONFIG_CPU_SOCKET_ISA
	uint8_t val8;

	*valp = (udata_t) (data_t) -1;

	switch (bs) {
	case 0x1:
		val8 = -1;
		sig_isa_bus_readb(cpssp->port_bus, cpssp, paddr + 0, &val8);
		*valp = val8 << 0;
		break;
	case 0x2:
		val8 = -1;
		sig_isa_bus_readb(cpssp->port_bus, cpssp, paddr + 1, &val8);
		*valp = val8 << 8;
		break;
	case 0x3:
		sig_isa_bus_readw(cpssp->port_bus, cpssp, paddr + 0, valp);
		break;
	default:
		assert(0); /* Mustn't happen. */
	}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	*valp = (udata_t) (data_t) -1;

	if (unlikely(sig_host_bus_mx(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, bs, valp) != 0)) {
		sig_host_bus_addr_type(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, SIG_HOST_BUS_MR);
		/* delay */
		sig_host_bus_read_data(cpssp->port_bus, cpssp, bs, valp);
	}

#elif defined CONFIG_CPU_SOCKET_HOST775
	*valp = (udata_t) (data_t) -1;

	if (unlikely(sig_host775_bus_mx(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, bs, valp) != 0)) {
		sig_host775_bus_addr_type(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, SIG_HOST775_BUS_MR);
		/* delay */
		sig_host775_bus_read_data(cpssp->port_bus, cpssp, bs, valp);
	}

#else
#error "Unknown socket."
#endif
	return 0;
}

static int
CHIP_(mr)(void *_cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	struct cpssp *cpssp = _cpssp;

#if defined CONFIG_CPU_SOCKET_ISA
	uint8_t val8;

	*valp = (udata_t) (data_t) -1;

	switch (bs) {
	case 0x1:
		val8 = -1;
		sig_isa_bus_readb(cpssp->port_bus, cpssp, paddr + 0, &val8);
		*valp = val8 << 0;
		break;
	case 0x2:
		val8 = -1;
		sig_isa_bus_readb(cpssp->port_bus, cpssp, paddr + 1, &val8);
		*valp = val8 << 8;
		break;
	case 0x3:
		sig_isa_bus_readw(cpssp->port_bus, cpssp, paddr + 0, valp);
		break;
	default:
		assert(0); /* Mustn't happen. */
	}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	*valp = (udata_t) (data_t) -1;

	if (unlikely(sig_host_bus_mr(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, bs, valp) != 0)) {
		sig_host_bus_addr_type(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, SIG_HOST_BUS_MR);
		/* delay */
		sig_host_bus_read_data(cpssp->port_bus, cpssp, bs, valp);
	}

#elif defined CONFIG_CPU_SOCKET_HOST775
	*valp = (udata_t) (data_t) -1;

	if (unlikely(sig_host775_bus_mr(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, bs, valp) != 0)) {
		sig_host775_bus_addr_type(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, SIG_HOST775_BUS_MR);
		/* delay */
		sig_host775_bus_read_data(cpssp->port_bus, cpssp, bs, valp);
	}

#else
#error "Unknown socket."
#endif
	return 0;
}

static int
CHIP_(mw)(void *_cpssp, paddr_t paddr, unsigned int bs, udata_t val)
{
	struct cpssp *cpssp = _cpssp;

#if defined CONFIG_CPU_SOCKET_ISA
	switch (bs) {
	case 0x1:
		sig_isa_bus_writeb(cpssp->port_bus, cpssp, paddr + 0, val >> 0);
		break;
	case 0x2:
		sig_isa_bus_writeb(cpssp->port_bus, cpssp, paddr + 1, val >> 8);
		break;
	case 0x3:
		sig_isa_bus_writew(cpssp->port_bus, cpssp, paddr + 0, val >> 0);
		break;
	default:
		assert(0); /* Mustn't happen. */
	}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	if (unlikely(sig_host_bus_mw(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, bs, val) != 0)) {
		sig_host_bus_addr_type(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, SIG_HOST_BUS_MW);
		/* delay */
		sig_host_bus_write_data(cpssp->port_bus, cpssp, bs, val);
	}

#elif defined CONFIG_CPU_SOCKET_HOST775
	if (unlikely(sig_host775_bus_mw(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, bs, val) != 0)) {
		sig_host775_bus_addr_type(cpssp->port_bus, cpssp, cpssp->core.smm, paddr, SIG_HOST775_BUS_MW);
		/* delay */
		sig_host775_bus_write_data(cpssp->port_bus, cpssp, bs, val);
	}

#else
#error "Unknown socket."
#endif
	return 0;
}

static int
CHIP_(mr_dummy)(void *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	*valp = (udata_t) (data_t) -1;

	if (CHIP_(mr)(cpssp, paddr, bs, valp)) {
		fprintf(stderr, "WARNING: No callback for physical address 0x%lx\n", (unsigned long) paddr);
	}

	return 0;
}

static void
CHIP_(map_r)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
#if defined CONFIG_CPU_SOCKET_ISA
	if (sig_isa_bus_map_r(cpssp->port_bus, cpssp, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(mr_dummy);
		*csp = cpssp;
		*haddrp = NULL;
	}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	if (sig_host_bus_map_r_check(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff)
	 || sig_host_bus_map_r(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(mr_dummy);
		*csp = cpssp;
		*haddrp = NULL;
	}

#elif defined CONFIG_CPU_SOCKET_HOST775
	if (sig_host775_bus_map_r_check(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff)
	 || sig_host775_bus_map_r(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(mr_dummy);
		*csp = cpssp;
		*haddrp = NULL;
	}
#else
#error "Unknown socket."
#endif

	assert(*cfp || *haddrp);

	if (*haddrp) {
		*haddrp += paddr & 0xfff;
	}
}

static int
CHIP_(mw_dummy)(void *cpssp, paddr_t paddr, unsigned int bs, udata_t val)
{
	if (CHIP_(mw)(cpssp, paddr, bs, val)) {
		fprintf(stderr, "WARNING: No callback for physical address 0x%lx\n", (unsigned long) paddr);
	}

	return 0;
}

static void
CHIP_(map_w)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t),
	void **csp,
	char **haddrp
)
{
#if defined CONFIG_CPU_SOCKET_ISA
	if (sig_isa_bus_map_w(cpssp->port_bus, cpssp, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(mw_dummy);
		*csp = cpssp;
		*haddrp = NULL;
	}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	if (sig_host_bus_map_w_check(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff)
	 || sig_host_bus_map_w(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(mw_dummy);
		*csp = cpssp;
		*haddrp = NULL;
	}

#elif defined CONFIG_CPU_SOCKET_HOST775
	if (sig_host775_bus_map_w_check(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff)
	 || sig_host775_bus_map_w(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(mw_dummy);
		*csp = cpssp;
		*haddrp = NULL;
	}
#else
#error "Unknown socket."
#endif

	assert(*cfp || *haddrp);

	if (*haddrp) {
		*haddrp += paddr & 0xfff;
	}
}

static int
CHIP_(map_x_dummy)(void *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	*valp = (udata_t) (data_t) -1;
	return 1;
}

static void
CHIP_(map_x)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
#if defined CONFIG_CPU_SOCKET_ISA
	if (sig_isa_bus_map_r(cpssp->port_bus, cpssp, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(map_x_dummy);
		*csp = NULL; /* Not used. */
		*haddrp = NULL;
	}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	if (sig_host_bus_map_x_check(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff)
	 || sig_host_bus_map_x(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(map_x_dummy);
		*csp = NULL; /* Not used. */
		*haddrp = NULL;
	}

#elif defined CONFIG_CPU_SOCKET_HOST775
	if (sig_host775_bus_map_x_check(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff)
	 || sig_host775_bus_map_x(cpssp->port_bus, cpssp, cpssp->core.smm, paddr & ~0xfff, cfp, csp, haddrp)) {
		*cfp = CHIP_(map_x_dummy);
		*csp = NULL; /* Not used. */
		*haddrp = NULL;
	}
#else
#error "Unknown socket."
#endif

	assert(*cfp || *haddrp);

	if (*haddrp) {
		*haddrp += paddr & 0xfff;
	}
}

/*
 * Callbacks for apic.
 */
static int
CHIP_(apic_bus_mx)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	return CHIP_(mx)(cpssp, paddr, bs, valp);
}

static int
CHIP_(apic_bus_mr)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	return CHIP_(mr)(cpssp, paddr, bs, valp);
}

static int
CHIP_(apic_bus_mw)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t val)
{
	return CHIP_(mw)(cpssp, paddr, bs, val);
}

static void
CHIP_(apic_bus_map_r)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(map_r)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(apic_bus_map_w)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t),
	void **csp,
	char **haddrp
)
{
	CHIP_(map_w)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(apic_bus_map_x)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(map_x)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(apic_core_irq_set)(struct cpssp *cpssp, unsigned int val)
{
	CHIP_(core_irq_set)(cpssp, val);
}

static void
CHIP_(apic_core_nmi_set)(struct cpssp *cpssp, unsigned int val)
{
	CHIP_(core_nmi_set)(cpssp, val);
}

#if defined CONFIG_CPU_APIC_SUPPORT && CONFIG_CPU_APIC_SUPPORT
static void
CHIP_(apic_core_smi_set)(struct cpssp *cpssp, unsigned int val)
{
	CHIP_(core_smi_set)(cpssp, val);
}
#endif /* defined CONFIG_CPU_APIC_SUPPORT && CONFIG_CPU_APIC_SUPPORT */

static void
CHIP_(apic_bus_ack)(struct cpssp *cpssp, uint8_t *vecp)
{
#if defined CONFIG_CPU_SOCKET_ISA
	sig_isa_bus_inta_addr(cpssp->port_bus, cpssp);
	sig_isa_bus_inta_data(cpssp->port_bus, cpssp, vecp);

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	sig_host_bus_inta_addr(cpssp->port_bus, cpssp);
	sig_host_bus_inta_data(cpssp->port_bus, cpssp, vecp);

#elif defined CONFIG_CPU_SOCKET_HOST775
	sig_host775_bus_inta_addr(cpssp->port_bus, cpssp);
	sig_host775_bus_inta_data(cpssp->port_bus, cpssp, vecp);
#else
#error "Unknown socket."
#endif
}

#if defined CONFIG_CPU_APIC_SUPPORT && CONFIG_CPU_APIC_SUPPORT
static void
CHIP_(apic_startup_by_apic)(struct cpssp *cpssp, uint8_t vec)
{
	CHIP_(core_startup)(cpssp, vec);
}

static void
CHIP_(apic_init_by_apic)(struct cpssp *cpssp)
{
	CHIP_(core_init_by_apic)(cpssp);
}
#endif /* defined CONFIG_CPU_APIC_SUPPORT && CONFIG_CPU_APIC_SUPPORT */

static void
CHIP_(apic_cache2_unmap)(struct cpssp *cpssp, paddr_t paddr, paddr_t len)
{
	CHIP_(cache2_unmap)(cpssp, paddr, len);
}

/*
 * Callbacks for cache2.
 */
static void
CHIP_(cache2_apic_mx)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	CHIP_(apic_mx)(cpssp, paddr, bs, valp);
}

static void
CHIP_(cache2_apic_mr)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	CHIP_(apic_mr)(cpssp, paddr, bs, valp);
}

static void
CHIP_(cache2_apic_mw)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t val)
{
	CHIP_(apic_mw)(cpssp, paddr, bs, val);
}

static void
CHIP_(cache2_apic_map_r)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(apic_map_r)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(cache2_apic_map_w)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t),
	void **csp,
	char **haddrp
)
{
	CHIP_(apic_map_w)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(cache2_apic_map_x)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(apic_map_x)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(cache2_mmu_unmap)(struct cpssp *cpssp, paddr_t paddr, paddr_t len)
{
	CHIP_(a20gate_unmap)(cpssp, paddr, len);
}

/*
 * Callbacks for a20gate.
 */
static void
CHIP_(a20gate_cache2_mx)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	CHIP_(cache2_mx)(cpssp, paddr, bs, valp);
}

static void
CHIP_(a20gate_cache2_mr)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	CHIP_(cache2_mr)(cpssp, paddr, bs, valp);
}

static void
CHIP_(a20gate_cache2_mw)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t val)
{
	CHIP_(cache2_mw)(cpssp, paddr, bs, val);
}

static void
CHIP_(a20gate_cache2_map_r)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(cache2_map_r)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(a20gate_cache2_map_w)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t),
	void **csp,
	char **haddrp
)
{
	CHIP_(cache2_map_w)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(a20gate_cache2_map_x)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(cache2_map_x)(cpssp, paddr, cfp, csp, haddrp);
}

#if 80386 <= CONFIG_CPU
static void
CHIP_(a20gate_mmu_flush_all)(struct cpssp *cpssp)
{
	CHIP_(mmui_tlb_flush)(cpssp, 1);
	CHIP_(mmud_tlb_flush)(cpssp, 1);
}
#endif /* 80386 <= CONFIG_CPU */

static void
CHIP_(a20gate_cache1_unmap)(struct cpssp *cpssp, paddr_t paddr, paddr_t len)
{
	CHIP_(cache1i_unmap)(cpssp, paddr, len);
	CHIP_(cache1d_unmap)(cpssp, paddr, len);
}

/*
 * Callbacks for mmui.
 */
#if 80486 <= CONFIG_CPU
static int
CHIP_(mmui_cr0_wp_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr0_wp_get)(cpssp);
}
#endif /* 80486 <= CONFIG_CPU */

static int
CHIP_(mmui_cr0_pg_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr0_pg_get)(cpssp);
}

static paddr_t
CHIP_(mmui_cr3_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr3_get)(cpssp);
}

#if defined CONFIG_CPU_PAE_SUPPORT && CONFIG_CPU_PAE_SUPPORT
static int
CHIP_(mmui_cr4_pae_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr4_pae_get)(cpssp);
}
#endif /* defined CONFIG_CPU_PAE_SUPPORT && CONFIG_CPU_PAE_SUPPORT */

#if defined CONFIG_CPU_PSE_SUPPORT && CONFIG_CPU_PSE_SUPPORT
static int
CHIP_(mmui_cr4_pse_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr4_pse_get)(cpssp);
}
#endif /* defined CONFIG_CPU_PSE_SUPPORT && CONFIG_CPU_PSE_SUPPORT */

#if defined CONFIG_CPU_PGE_SUPPORT && CONFIG_CPU_PGE_SUPPORT
static int
CHIP_(mmui_cr4_pge_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr4_pge_get)(cpssp);
}
#endif /* defined CONFIG_CPU_PGE_SUPPORT && CONFIG_CPU_PGE_SUPPORT */

#if defined CONFIG_CPU_LM_SUPPORT && CONFIG_CPU_LM_SUPPORT
static int
CHIP_(mmui_efer_lme_get)(struct cpssp *cpssp)
{
	return CHIP_(core_efer_lme_get)(cpssp);
}
#endif /* defined CONFIG_CPU_LM_SUPPORT && CONFIG_CPU_LM_SUPPORT */

#if defined CONFIG_CPU_NX_SUPPORT && CONFIG_CPU_NX_SUPPORT
static int
CHIP_(mmui_efer_nxe_get)(struct cpssp *cpssp)
{
	return CHIP_(core_efer_nxe_get)(cpssp);
}
#endif /* defined CONFIG_CPU_NX_SUPPORT && CONFIG_CPU_NX_SUPPORT */

#if defined CONFIG_CPU_MTRR_SUPPORT && CONFIG_CPU_MTRR_SUPPORT
static uint8_t
CHIP_(mmui_type)(struct cpssp *cpssp, paddr_t paddr)
{
	return CHIP_(mtrr_type)(cpssp, paddr);
}
#endif /* defined CONFIG_CPU_MTRR_SUPPORT && CONFIG_CPU_MTRR_SUPPORT */

static void
CHIP_(mmui_mr)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	CHIP_(a20gate_mr)(cpssp, paddr, bs, valp);
}

static void
CHIP_(mmui_mw)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t val)
{
	CHIP_(a20gate_mw)(cpssp, paddr, bs, val);
}

#if 80486 <= CONFIG_CPU
static void
CHIP_(mmui_cache1_invlpg)(struct cpssp *cpssp, vaddr_t vaddr)
{
	CHIP_(cache1i_invlpg)(cpssp, vaddr);
}
#endif /* 80486 <= CONFIG_CPU */

static void
CHIP_(mmui_cache1_tlb_flush)(struct cpssp *cpssp, int all)
{
	CHIP_(cache1i_tlb_flush)(cpssp, all);
}

/*
 * Callbacks for mmud.
 */
#if 80486 <= CONFIG_CPU
static int
CHIP_(mmud_cr0_wp_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr0_wp_get)(cpssp);
}
#endif /* 80486 <= CONFIG_CPU */

static int
CHIP_(mmud_cr0_pg_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr0_pg_get)(cpssp);
}

static paddr_t
CHIP_(mmud_cr3_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr3_get)(cpssp);
}

#if defined CONFIG_CPU_PAE_SUPPORT && CONFIG_CPU_PAE_SUPPORT
static int
CHIP_(mmud_cr4_pae_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr4_pae_get)(cpssp);
}
#endif /* defined CONFIG_CPU_PAE_SUPPORT && CONFIG_CPU_PAE_SUPPORT */

#if defined CONFIG_CPU_PSE_SUPPORT && CONFIG_CPU_PSE_SUPPORT
static int
CHIP_(mmud_cr4_pse_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr4_pse_get)(cpssp);
}
#endif /* defined CONFIG_CPU_PSE_SUPPORT && CONFIG_CPU_PSE_SUPPORT */

#if defined CONFIG_CPU_PGE_SUPPORT && CONFIG_CPU_PGE_SUPPORT
static int
CHIP_(mmud_cr4_pge_get)(struct cpssp *cpssp)
{
	return CHIP_(core_cr4_pge_get)(cpssp);
}
#endif /* defined CONFIG_CPU_PGE_SUPPORT && CONFIG_CPU_PGE_SUPPORT */

#if defined CONFIG_CPU_LM_SUPPORT && CONFIG_CPU_LM_SUPPORT
static int
CHIP_(mmud_efer_lme_get)(struct cpssp *cpssp)
{
	return CHIP_(core_efer_lme_get)(cpssp);
}
#endif /* defined CONFIG_CPU_LM_SUPPORT && CONFIG_CPU_LM_SUPPORT */

#if defined CONFIG_CPU_NX_SUPPORT && CONFIG_CPU_NX_SUPPORT
static int
CHIP_(mmud_efer_nxe_get)(struct cpssp *cpssp)
{
	return CHIP_(core_efer_nxe_get)(cpssp);
}
#endif /* defined CONFIG_CPU_NX_SUPPORT && CONFIG_CPU_NX_SUPPORT */

#if defined CONFIG_CPU_MTRR_SUPPORT && CONFIG_CPU_MTRR_SUPPORT
static uint8_t
CHIP_(mmud_type)(struct cpssp *cpssp, paddr_t paddr)
{
	return CHIP_(mtrr_type)(cpssp, paddr);
}
#endif /* defined CONFIG_CPU_MTRR_SUPPORT && CONFIG_CPU_MTRR_SUPPORT */

static void
CHIP_(mmud_mr)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t *valp)
{
	CHIP_(a20gate_mr)(cpssp, paddr, bs, valp);
}

static void
CHIP_(mmud_mw)(struct cpssp *cpssp, paddr_t paddr, unsigned int bs, udata_t val)
{
	CHIP_(a20gate_mw)(cpssp, paddr, bs, val);
}

#if 80486 <= CONFIG_CPU
static void
CHIP_(mmud_cache1_invlpg)(struct cpssp *cpssp, vaddr_t vaddr)
{
	CHIP_(cache1d_invlpg)(cpssp, vaddr);
}
#endif /* 80486 <= CONFIG_CPU */

static void
CHIP_(mmud_cache1_tlb_flush)(struct cpssp *cpssp, int all)
{
	CHIP_(cache1d_tlb_flush)(cpssp, all);
}

/*
 * Callbacks for cache1i.
 */
static int
CHIP_(cache1i_mmu_map)(struct cpssp *cpssp, vaddr_t vaddr, unsigned int wflag, unsigned int uflag, paddr_t *paddrp, uint16_t *errp)
{
	return CHIP_(mmui_map)(cpssp, vaddr, wflag, uflag, 1, paddrp, errp);
}

static void
CHIP_(cache1i_a20gate_map_x)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(a20gate_map_x)(cpssp, paddr, cfp, csp, haddrp);
}

#if 80486 <= CONFIG_CPU
static void
CHIP_(cache1i_align_invlpg)(struct cpssp *cpssp, vaddr_t vaddr)
{
	CHIP_(code_invlpg)(cpssp, vaddr);
}
#endif /* 80486 <= CONFIG_CPU */

static void
CHIP_(cache1i_align_tlb_flush)(struct cpssp *cpssp, int all)
{
	CHIP_(code_tlb_flush)(cpssp, all);
}

static void
CHIP_(cache1i_align_unmap)(struct cpssp *cpssp, paddr_t paddr, paddr_t len)
{
	CHIP_(code_unmap)(cpssp, paddr, len);
}

/*
 * Callbacks for cache1d.
 */
static int
CHIP_(cache1d_mmu_map)(struct cpssp *cpssp, vaddr_t vaddr, unsigned int wflag, unsigned int uflag, paddr_t *paddrp, uint16_t *errp)
{
	return CHIP_(mmud_map)(cpssp, vaddr, wflag, uflag, 0, paddrp, errp);
}

static void
CHIP_(cache1d_a20gate_map_r)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t *),
	void **csp,
	char **haddrp
)
{
	CHIP_(a20gate_map_r)(cpssp, paddr, cfp, csp, haddrp);
}

static void
CHIP_(cache1d_a20gate_map_w)(
	struct cpssp *cpssp,
	paddr_t paddr,
	int (**cfp)(void *, paddr_t, unsigned int, udata_t),
	void **csp,
	char **haddrp
)
{
	CHIP_(a20gate_map_w)(cpssp, paddr, cfp, csp, haddrp);
}

#if 80486 <= CONFIG_CPU
static void
CHIP_(cache1d_align_invlpg)(struct cpssp *cpssp, vaddr_t vaddr)
{
	CHIP_(data_invlpg)(cpssp, vaddr);
}
#endif /* 80486 <= CONFIG_CPU */

static void
CHIP_(cache1d_align_tlb_flush)(struct cpssp *cpssp, int all)
{
	CHIP_(data_tlb_flush)(cpssp, all);
}

static void
CHIP_(cache1d_align_unmap)(struct cpssp *cpssp, paddr_t paddr, paddr_t len)
{
	CHIP_(data_unmap)(cpssp, paddr, len);
}

/*
 * Callbacks for align_io.
 */
static void
CHIP_(align_bus_ior)(struct cpssp *cpssp, paddr_t port, unsigned int bs, udata_t *valp)
{
	cpssp->mem_write_pc = (unsigned long) __builtin_return_address(0);

	CHIP_(ior)(cpssp, port, bs, valp);
}

static void
CHIP_(align_bus_iow)(struct cpssp *cpssp, paddr_t port, unsigned int bs, udata_t val)
{
	cpssp->mem_write_pc = (unsigned long) __builtin_return_address(0);

	CHIP_(iow)(cpssp, port, bs, val);
}

/*
 * Callbacks for align_code.
 */
/* FIXME */

/*
 * Callbacks for align_data.
 */
/* FIXME */

/*
 * Callbacks for core.
 */
static uint8_t
CHIP_(core_ack)(struct cpssp *cpssp)
{
	return CHIP_(apic_irq_ack)(cpssp);
}

#if defined CONFIG_CPU_APIC_SUPPORT && CONFIG_CPU_APIC_SUPPORT
static int
CHIP_(core_apic_wrmsr)(struct cpssp *cpssp, uint32_t ecx, uint64_t val)
{
	return CHIP_(apic_wrmsr)(cpssp, ecx, val);
}

static int
CHIP_(core_apic_rdmsr)(struct cpssp *cpssp, uint32_t ecx, uint64_t *valp)
{
	return CHIP_(apic_rdmsr)(cpssp, ecx, valp);
}

static void
CHIP_(core_apic_tpr_set)(struct cpssp *cpssp, uint8_t val)
{
	CHIP_(apic_tpr_set)(cpssp, val);
}

#if 0 /* Not used. */
static uint8_t
core_apic_tpr_get(struct cpssp *cpssp)
{
	return apic_tpr_get(cpssp);
}
#endif /* Not used. */
#endif /* defined CONFIG_CPU_APIC_SUPPORT && CONFIG_CPU_APIC_SUPPORT */

#if defined CONFIG_CPU_MTRR_SUPPORT && CONFIG_CPU_MTRR_SUPPORT
static int
CHIP_(core_mtrr_wrmsr)(struct cpssp *cpssp, uint32_t ecx, uint64_t val)
{
	return CHIP_(mtrr_wrmsr)(cpssp, ecx, val);
}

static int
CHIP_(core_mtrr_rdmsr)(struct cpssp *cpssp, uint32_t ecx, uint64_t *valp)
{
	return CHIP_(mtrr_rdmsr)(cpssp, ecx, valp);
}
#endif /* defined CONFIG_CPU_MTRR_SUPPORT && CONFIG_CPU_MTRR_SUPPORT */

static void
CHIP_(core_mmu_tlb_flush)(struct cpssp *cpssp, int all)
{
	CHIP_(mmui_tlb_flush)(cpssp, all);
	CHIP_(mmud_tlb_flush)(cpssp, all);
}

#if 80486 <= CONFIG_CPU
static void
CHIP_(core_mmu_invlpg)(struct cpssp *cpssp, vaddr_t vaddr)
{
	CHIP_(mmui_invlpg)(cpssp, vaddr);
	CHIP_(mmud_invlpg)(cpssp, vaddr);
}
#endif /* 80486 <= CONFIG_CPU */


#define BEHAVIOR

#define NAME		apic
#define NAME_(x)	CONC(CHIP, apic, x)
#include "arch_gen_cpu_x86_apic.c"
#undef NAME_
#undef NAME

#if defined CONFIG_CPU_L2_SIZE
#define CONFIG_CACHE2_ASSOC	CONFIG_CPU_L2_ASSOC
#define CONFIG_CACHE2_SIZE	CONFIG_CPU_L2_SIZE
#define CONFIG_CACHE2_LINE_SIZE	CONFIG_CPU_CACHE_LINE_SIZE
#endif
#define NAME		cache2
#define NAME_(x)	CONC(CHIP, cache2, x)
#include "arch_gen_cpu_x86_cache2.c"
#undef NAME_
#undef NAME
#if defined CONFIG_CPU_L2_SIZE
#undef CONFIG_CACHE2_LINE_SIZE
#undef CONFIG_CACHE2_SIZE
#undef CONFIG_CACHE2_ASSOC
#endif

#define NAME		mtrr
#define NAME_(x)	CONC(CHIP, mtrr, x)
#include "arch_gen_cpu_x86_mtrr.c"
#undef NAME_
#undef NAME

#define NAME		a20gate
#define NAME_(x)	CONC(CHIP, a20gate, x)
#include "arch_gen_cpu_x86_a20gate.c"
#undef NAME_
#undef NAME

#define NAME		mmui
#define NAME_(x)	CONC(CHIP, mmui, x)
#ifdef CONFIG_CPU_TLBI_SIZE
#define CONFIG_MMU_TLB_ASSOC	CONFIG_CPU_TLBI_ASSOC
#define CONFIG_MMU_TLB_SIZE	CONFIG_CPU_TLBI_SIZE
#elif defined CONFIG_CPU_TLBI4M_SIZE && defined CONFIG_CPU_TLBI4K_SIZE
#define CONFIG_MMU_TLB4K_ASSOC	CONFIG_CPU_TLBI4K_ASSOC
#define CONFIG_MMU_TLB4K_SIZE	CONFIG_CPU_TLBI4K_SIZE
#define CONFIG_MMU_TLB4M_ASSOC	CONFIG_CPU_TLBI4M_ASSOC
#define CONFIG_MMU_TLB4M_SIZE	CONFIG_CPU_TLBI4M_SIZE
#endif
#include "arch_gen_cpu_x86_mmu.c"
#undef CONFIG_MMU_TLB4M_SIZE
#undef CONFIG_MMU_TLB4M_ASSOC
#undef CONFIG_MMU_TLB4K_SIZE
#undef CONFIG_MMU_TLB4K_ASSOC
#undef CONFIG_MMU_TLB_SIZE
#undef CONFIG_MMU_TLB_ASSOC
#undef NAME_
#undef NAME

#define NAME		mmud
#define NAME_(x)	CONC(CHIP, mmud, x)
#ifdef CONFIG_CPU_TLBD_SIZE
#define CONFIG_MMU_TLB_ASSOC	CONFIG_CPU_TLBD_ASSOC
#define CONFIG_MMU_TLB_SIZE	CONFIG_CPU_TLBD_SIZE
#elif defined CONFIG_CPU_TLBD4M_SIZE && defined CONFIG_CPU_TLBD4K_SIZE
#define CONFIG_MMU_TLB4K_ASSOC	CONFIG_CPU_TLBD4K_ASSOC
#define CONFIG_MMU_TLB4K_SIZE	CONFIG_CPU_TLBD4K_SIZE
#define CONFIG_MMU_TLB4M_ASSOC	CONFIG_CPU_TLBD4M_ASSOC
#define CONFIG_MMU_TLB4M_SIZE	CONFIG_CPU_TLBD4M_SIZE
#endif
#include "arch_gen_cpu_x86_mmu.c"
#undef CONFIG_MMU_TLB4M_SIZE
#undef CONFIG_MMU_TLB4M_ASSOC
#undef CONFIG_MMU_TLB4K_SIZE
#undef CONFIG_MMU_TLB4K_ASSOC
#undef CONFIG_MMU_TLB_SIZE
#undef CONFIG_MMU_TLB_ASSOC
#undef NAME_
#undef NAME

#define NAME		cache1i
#define NAME_(x)	CONC(CHIP, cache1i, x)
#define CONFIG_CODE
#ifdef CONFIG_CPU_L1I_SIZE
#define CONFIG_SIZE	CONFIG_CPU_L1I_SIZE
#define CONFIG_ASSOC	CONFIG_CPU_L1I_ASSOC
#endif
#include "arch_gen_cpu_x86_cache1.c"
#ifdef CONFIG_CPU_L1I_SIZE
#undef CONFIG_ASSOC
#undef CONFIG_SIZE
#endif
#undef CONFIG_CODE
#undef NAME_
#undef NAME

#define NAME		cache1d
#define NAME_(x)	CONC(CHIP, cache1d, x)
#define CONFIG_DATA
#ifdef CONFIG_CPU_L1D_SIZE
#define CONFIG_SIZE	CONFIG_CPU_L1D_SIZE
#define CONFIG_ASSOC	CONFIG_CPU_L1D_ASSOC
#endif
#include "arch_gen_cpu_x86_cache1.c"
#ifdef CONFIG_CPU_L1D_SIZE
#undef CONFIG_ASSOC
#undef CONFIG_SIZE
#endif
#undef CONFIG_DATA
#undef NAME_
#undef NAME

#define NAME		align
#define NAME_(x)	CONC(CHIP, align, x)
#include "arch_gen_cpu_x86_align_io.c"
#undef NAME_
#undef NAME

#define NAME		align
#define NAME_(x)	CONC(CHIP, align, x)
#include "arch_gen_cpu_x86_align.c"
#undef NAME_
#undef NAME

#define NAME		CHIP /* FIXME */
#define NAME_(x)	CHIP_(x) /* FIXME */
#include "arch_gen_cpu_x86_fpu.c"
#include "arch_gen_cpu_x86_core.c"
#include "cpu_jit_buffer.c"
#include "cpu_jit_compile.c"
#undef NAME_
#undef NAME

#undef BEHAVIOR

#if 80386 <= CONFIG_CPU
static void
CHIP_(a20m_set)(void *_cpssp, unsigned int a20_state)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(a20gate_gate_set)(cpssp, a20_state);
}
#endif /* 80386 <= CONFIG_CPU */

#if defined CONFIG_CPU_SOCKET_ISA
static int
CHIP_(map_r_check)(void *_cpssp, uint32_t paddr)
{
	// fprintf(stderr, "%s\n", __FUNCTION__);
	return 0; /* Always ok for now. */
}

static int
CHIP_(map_w_check)(void *_cpssp, uint32_t paddr)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(tb_invalidate_phys_page)(cpssp, paddr);

	return 0; /* Always ok for now. */
}

static void
CHIP_(unmap)(void *_cpssp, uint32_t paddr, uint32_t len)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_unmap)(cpssp, paddr, len);
}

#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
static int
CHIP_(map_r_check)(void *_cpssp, unsigned int smm, uint32_t paddr)
{
	// fprintf(stderr, "%s\n", __FUNCTION__);
	return 0; /* Always ok for now. */
}

static int
CHIP_(map_w_check)(void *_cpssp, unsigned int smm, uint32_t paddr)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(tb_invalidate_phys_page)(cpssp, paddr);

	return 0; /* Always ok for now. */
}

static int
CHIP_(map_x_check)(void *_cpssp, unsigned int smm, uint32_t paddr)
{
	// fprintf(stderr, "%s\n", __FUNCTION__);
	return 0; /* Always ok for now. */
}

static void
CHIP_(unmap)(void *_cpssp, uint32_t paddr, uint32_t len)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_unmap)(cpssp, paddr, len);
}

#elif defined CONFIG_CPU_SOCKET_HOST775
static int
CHIP_(map_r_check)(void *_cpssp, unsigned int smm, uint64_t paddr)
{
	return 0; /* Always ok for now. */
}

static int
CHIP_(map_w_check)(void *_cpssp, unsigned int smm, uint64_t paddr)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(tb_invalidate_phys_page)(cpssp, paddr);

	return 0; /* Always ok for now. */
}

static int
CHIP_(map_x_check)(void *_cpssp, unsigned int smm, uint64_t paddr)
{
	return 0; /* Always ok for now. */
}

static void
CHIP_(unmap)(void *_cpssp, uint64_t paddr, uint64_t len)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_unmap)(cpssp, paddr, len);
}

#else
#error "Unknown socket."
#endif

static void
CHIP_(lint0_set)(void *_cpssp, unsigned int val)
{
	struct cpssp *cpssp = _cpssp;

	assert(val == 0 || val == 1);

	CHIP_(apic_lint0_set)(cpssp, val);
}

static void
CHIP_(lint1_set)(void *_cpssp, unsigned int val)
{
	struct cpssp *cpssp = _cpssp;

	assert(val == 0 || val == 1);

	CHIP_(apic_lint1_set)(cpssp, val);
}

#if 80386 <= CONFIG_CPU
static void
CHIP_(smi_set)(void *_cpssp, unsigned int val)
{
	struct cpssp *cpssp = _cpssp;

	assert(val == 0 || val == 1);

	CHIP_(core_smi_set)(cpssp, val);
}
#endif /* 80386 <= CONFIG_CPU */

#if 80486 <= CONFIG_CPU && CONFIG_CPU_APIC_SUPPORT
static void
CHIP_(eoi_receive)(void *_cpssp, uint8_t vector)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_eoi_receive)(cpssp, vector);
}

static void
CHIP_(msg0_receive)(
	void *_cpssp,
	unsigned int destination_mode,
	unsigned int delivery_mode,
	unsigned int level,
	unsigned int trigger_mode,
	uint8_t vector,
	uint8_t destination
)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_msg0_receive)(cpssp, destination_mode, delivery_mode, level,
			trigger_mode, vector, destination);
}

static void
CHIP_(status0_receive)(void *_cpssp, unsigned int status)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_status0_receive)(cpssp, status);
}

static void
CHIP_(msg1_receive)(void *_cpssp, uint8_t processor_priority)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_msg1_receive)(cpssp, processor_priority);
}

static void
CHIP_(status1_receive)(void *_cpssp, unsigned int status)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(apic_status1_receive)(cpssp, status);
}
#endif /* 80486 <= CONFIG_CPU && CONFIG_CPU_APIC_SUPPORT */

static void
CHIP_(power_set)(void *_cpssp, unsigned int val)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(core_power_set)(cpssp, val);
}

static void
CHIP_(n_reset_set)(void *_cpssp, unsigned int n_val)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(core_n_reset_set)(cpssp, n_val);
}

#if 80386 < CONFIG_CPU
static void
CHIP_(n_init_set)(void *_cpssp, unsigned int n_val)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(core_n_init_set)(cpssp, n_val);
}
#endif /* 80386 <= CONFIG_CPU */

static void
CHIP_(n_ignne_set)(void *_cpssp, unsigned int n_val)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(core_n_ignne_set)(cpssp, n_val);
}

void *
CHIP_(create)(
	const char *name,
	struct sig_manage *port_manage,
	struct sig_std_logic *port_power,
	struct sig_std_logic *port_n_reset,
#if 80386 < CONFIG_CPU
	struct sig_std_logic *port_n_init,
#endif
	struct sig_std_logic *port_irq,
	struct sig_std_logic *port_nmi,
#if 80386 <= CONFIG_CPU
	struct sig_std_logic *port_smi,
#endif
	struct sig_std_logic *port_n_ferr,
	struct sig_std_logic *port_n_ignne,
#if 80386 <= CONFIG_CPU
	struct sig_std_logic *port_a20,
#endif
#if 80486 <= CONFIG_CPU && CONFIG_CPU_APIC_SUPPORT
	struct sig_icc_bus *port_icc,
#endif
#if defined CONFIG_CPU_SOCKET_ISA
	struct sig_isa_bus *port_bus
#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	struct sig_host_bus *port_bus
#elif defined CONFIG_CPU_SOCKET_HOST775
	struct sig_host775_bus *port_bus
#else
#error "Unknown socket."
#endif
)
{
	/* APIC */
	static const struct sig_std_logic_funcs lint0_func = {
		.boolean_or_set = CHIP_(lint0_set),
	};
	static const struct sig_std_logic_funcs lint1_func = {
		.boolean_or_set = CHIP_(lint1_set),
	};
#if 80386 <= CONFIG_CPU
	static const struct sig_std_logic_funcs smi_func = {
		.boolean_or_set = CHIP_(smi_set),
	};
#endif /* 80386 <= CONFIG_CPU */
#if 80486 <= CONFIG_CPU && CONFIG_CPU_APIC_SUPPORT
	static const struct sig_icc_bus_funcs icc_funcs = {
		.eoi = CHIP_(eoi_receive),
		.msg0 = CHIP_(msg0_receive),
		.status0 = CHIP_(status0_receive),
		.msg1 = CHIP_(msg1_receive),
		.status1 = CHIP_(status1_receive),
	};
#endif /* 80486 <= CONFIG_CPU && CONFIG_CPU_APIC_SUPPORT */

	/* Core */
	static const struct sig_manage_funcs manage_funcs = {
		.connect = CHIP_(connect),
		.disconnect = CHIP_(disconnect),
	};
	static const struct sig_std_logic_funcs power_funcs = {
		.boolean_or_set = CHIP_(power_set),
	};
	static const struct sig_std_logic_funcs n_reset_funcs = {
		.boolean_or_set = CHIP_(n_reset_set),
	};
#if 80386 < CONFIG_CPU
	static const struct sig_std_logic_funcs n_init_funcs = {
		.boolean_or_set = CHIP_(n_init_set),
	};
#endif
	static const struct sig_std_logic_funcs n_ignne_funcs = {
		.boolean_or_set = CHIP_(n_ignne_set),
	};

#if 80386 <= CONFIG_CPU
	/* MMU */
	static const struct sig_std_logic_funcs a20_func = {
		.boolean_or_set = CHIP_(a20m_set),
	};
#endif

	/* I/O */
#if defined CONFIG_CPU_SOCKET_ISA
	static const struct sig_isa_bus_funcs main_funcs = {
		.map_r_check = CHIP_(map_r_check),
		.map_w_check = CHIP_(map_w_check),
		.unmap = CHIP_(unmap),
	};
#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	static const struct sig_host_bus_funcs main_funcs = {
		.map_r_check = CHIP_(map_r_check),
		.map_w_check = CHIP_(map_w_check),
		.map_x_check = CHIP_(map_x_check),
		.unmap = CHIP_(unmap),
	};
#elif defined CONFIG_CPU_SOCKET_HOST775
	static const struct sig_host775_bus_funcs main_funcs = {
		.map_r_check = CHIP_(map_r_check),
		.map_w_check = CHIP_(map_w_check),
		.map_x_check = CHIP_(map_x_check),
		.unmap = CHIP_(unmap),
	};
#endif
	static unsigned int nr = 0;
	struct cpssp *cpssp;

	cpssp = shm_palloc(sizeof(*cpssp), SHM_CODE);
	assert(cpssp);

	system_name_push(name);
	cpssp->id = nr++;

	/* Configuration */
	/* FIXME */
	cpssp->apic_cluster_id = 1;
	cpssp->apic_arbitration_id = cpssp->id;

	cpssp->process.inst_hz = CONFIG_CPU_FREQ;

	sig_manage_connect(port_manage, cpssp, &manage_funcs);

	CHIP_(apic_create)(cpssp);

	cpssp->sig_n_ferr = port_n_ferr;
#if 80486 <= CONFIG_CPU && CONFIG_CPU_APIC_SUPPORT
	cpssp->icc_bus = port_icc;
#endif
	cpssp->port_bus = port_bus;

	CHIP_(jit_buffer_init)(cpssp);
	CHIP_(jit_compile_init)(cpssp);
	CHIP_(cache2_create)(cpssp);
	CHIP_(a20gate_create)(cpssp);
#if 80486 <= CONFIG_CPU && CONFIG_CPU_MTRR_SUPPORT
	CHIP_(mtrr_create)(cpssp);
#endif
	CHIP_(mmui_create)(cpssp);
	CHIP_(mmud_create)(cpssp);
	CHIP_(cache1i_create)(cpssp);
	CHIP_(cache1d_create)(cpssp);

	/* Output signals. */
	sig_std_logic_connect_out(cpssp->sig_n_ferr, cpssp, SIG_STD_LOGIC_L);

	/* Cycle signals. */
#if defined CONFIG_CPU_SOCKET_ISA
	sig_isa_bus_connect(cpssp->port_bus, cpssp, &main_funcs);
#elif defined CONFIG_CPU_SOCKET_HOST \
   || defined CONFIG_CPU_SOCKET_SLOT1
	sig_host_bus_connect(cpssp->port_bus, cpssp, &main_funcs);
#elif defined CONFIG_CPU_SOCKET_HOST775
	sig_host775_bus_connect(cpssp->port_bus, cpssp, &main_funcs);
#else
#error "Unknown socket."
#endif
#if 80486 <= CONFIG_CPU && CONFIG_CPU_APIC_SUPPORT
	sig_icc_bus_connect(cpssp->icc_bus, cpssp, &icc_funcs);
#endif

	/* Input signals. */
	sig_std_logic_connect_in(port_power, cpssp, &power_funcs);
	sig_std_logic_connect_in(port_n_reset, cpssp, &n_reset_funcs);
#if 80386 < CONFIG_CPU /* FIXME */
	sig_std_logic_connect_in(port_n_init, cpssp, &n_init_funcs);
#endif

	sig_std_logic_connect_in(port_irq, cpssp, &lint0_func);
	sig_std_logic_connect_in(port_nmi, cpssp, &lint1_func);
#if 80386 <= CONFIG_CPU
	sig_std_logic_connect_in(port_smi, cpssp, &smi_func);
#endif

	sig_std_logic_connect_in(port_n_ignne, cpssp, &n_ignne_funcs);

#if 80386 <= CONFIG_CPU
	sig_std_logic_connect_in(port_a20, cpssp, &a20_func);
#endif

	sched_process_init(&cpssp->process, CHIP_(step), cpssp);

	system_name_pop();

	return cpssp;
}

void
CHIP_(destroy)(void *_cpssp)
{
	struct cpssp *cpssp = _cpssp;

	CHIP_(cache1i_destroy)(cpssp);
	CHIP_(cache1d_destroy)(cpssp);
	CHIP_(mmui_destroy)(cpssp);
	CHIP_(mmud_destroy)(cpssp);
	CHIP_(a20gate_destroy)(cpssp);
#if 80486 <= CONFIG_CPU && CONFIG_CPU_MTRR_SUPPORT
	CHIP_(mtrr_destroy)(cpssp);
#endif
	CHIP_(cache2_destroy)(cpssp);
	CHIP_(apic_destroy)(cpssp);

	shm_pfree(cpssp);
}

void
CHIP_(suspend)(void *_cpssp, FILE *fp)
{
	struct cpssp *cpssp = _cpssp;

	generic_suspend(cpssp, sizeof(*cpssp), fp);
}

void
CHIP_(resume)(void *_cpssp, FILE *fp)
{
	struct cpssp *cpssp = _cpssp;

	generic_resume(cpssp, sizeof(*cpssp), fp);
}

#undef DEBUG_BIOS_POST_CODE
