#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "sl82c460.h"

static struct {
	int reg_idx;
	uint8_t regs[256];
} sl82c460;

static void sl82c460_shadow_set(uint32_t base, uint32_t size, int state) {
	switch (state) {
	case 0:mem_set_mem_state(base, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
		break;
	case 1:mem_set_mem_state(base, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
		break;
	case 2:mem_set_mem_state(base, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
		break;
	case 3:mem_set_mem_state(base, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
		break;
	}

}

static void sl82c460_shadow_recalc() {
	sl82c460_shadow_set(0xc0000, 0x4000, sl82c460.regs[0x18] & 3);
	sl82c460_shadow_set(0xc4000, 0x4000, (sl82c460.regs[0x18] >> 2) & 3);
	sl82c460_shadow_set(0xc8000, 0x4000, (sl82c460.regs[0x18] >> 4) & 3);
	sl82c460_shadow_set(0xcc000, 0x4000, (sl82c460.regs[0x18] >> 6) & 3);
	sl82c460_shadow_set(0xd0000, 0x4000, sl82c460.regs[0x19] & 3);
	sl82c460_shadow_set(0xd4000, 0x4000, (sl82c460.regs[0x19] >> 2) & 3);
	sl82c460_shadow_set(0xd8000, 0x4000, (sl82c460.regs[0x19] >> 4) & 3);
	sl82c460_shadow_set(0xdc000, 0x4000, (sl82c460.regs[0x19] >> 6) & 3);
	sl82c460_shadow_set(0xe0000, 0x10000, (sl82c460.regs[0x1b] >> 4) & 3);
	sl82c460_shadow_set(0xf0000, 0x10000, (sl82c460.regs[0x1b] >> 2) & 3);
}

static void sl82c460_write(uint16_t addr, uint8_t val, void *p) {
	if (!(addr & 1))
		sl82c460.reg_idx = val;
	else {
//                pclog("SL82C460 write %02x %02x\n", sl82c460.reg_idx, val);
		sl82c460.regs[sl82c460.reg_idx] = val;

		switch (sl82c460.reg_idx) {
		case 0x18:
		case 0x19:
		case 0x1b:sl82c460_shadow_recalc();
			break;
		}
	}
}

static uint8_t sl82c460_read(uint16_t addr, void *p) {
	if (!(addr & 1))
		return sl82c460.reg_idx;

	return sl82c460.regs[sl82c460.reg_idx];
}

void sl82c460_init() {
	memset(&sl82c460, 0, sizeof(sl82c460));
	io_sethandler(0x00a8, 0x0002, sl82c460_read, NULL, NULL, sl82c460_write, NULL, NULL, NULL);
}
