/*Arculator 2.2 by Sarah Walker
  Memory read/write functions*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "arc.h"
#include "arm.h"
#include "82c711.h"
#include "82c711_fdc.h"
#include "config.h"
#include "cp15.h"
#include "eterna.h"
#include "ide.h"
#include "ioc.h"
#include "ioeb.h"
#include "joystick.h"
#include "lc.h"
#include "memc.h"
#include "podules.h"
#include "printer.h"
#include "serial.h"
#include "st506.h"
#include "vidc.h"
#include "wd1770.h"

uint64_t mem_speed[16384][2];

int mem_dorefresh;

uint64_t mem_spd_multi;
uint64_t mem_spd_multi_2;
uint64_t mem_spd_multi_5;
uint64_t mem_spd_multi_32;

static int mem_romspeed_n, mem_romspeed_s;


uint8_t backplane_mask;
int bank;
int ddensity;
// static char err2[256];
FILE *olog;
int fdcside;
int realmemsize;

uint32_t *ram,*rom;
uint8_t *rom_5th_column;
uint8_t *rom_arcrom;
uint8_t *mempoint[0x4000];
uint8_t memstat[0x4000];
int memmode;

static void mem_recalc_mem_spd_multi(void)
{
	mem_spd_multi = arm_has_cp15 ? (((uint64_t)speed_mhz << 32) / arm_mem_speed) : (1ull << 32);
	/*This is very Not Nice, but avoids extremely frequent 64-bit multiplies in run_dma().*/
	mem_spd_multi_2 = 2 * mem_spd_multi;
	mem_spd_multi_5 = 5 * mem_spd_multi;
	mem_spd_multi_32 = 32 * mem_spd_multi;
}

void initmem(int memsize)
{
	int c;

	rpclog("initmem %i\n", memsize);
	realmemsize=memsize;
	ram=(uint32_t *)malloc(memsize*1024);
	rom=(uint32_t *)malloc(0x200000);
	rom_arcrom = malloc(0x10000);
	rom_5th_column = (uint8_t *)malloc(0x20000);
	for (c=0;c<0x4000;c++) memstat[c]=0;
	resetpagesize(0);
	for (c = 0x3800; c < 0x3fc0; c++)
		memstat[c] = 5;
	for (c = 0x3800; c < 0x4000; c++)
		mempoint[c] = ((uint8_t *)&rom[(c & 0x1FF) << 10]) - (c << 12);
	for (c = 0x3fc0; c < 0x4000; c++) /*Map support ROM at end of address space*/
		memstat[c] = support_rom_enabled ? 0 : 5;

	memset(ram,0,memsize*1024);
	memstat[0]=1;
	mempoint[0] = (uint8_t *)rom;
	realmemsize=memsize;


	mem_recalc_mem_spd_multi();
	for (c = 0; c < 0x3000; c++)
	{
		mem_speed[c][0] = 1 * mem_spd_multi;
		mem_speed[c][1] = 2 * mem_spd_multi;
	}
	for (c = 0x3000; c < 0x3800; c++)
		mem_speed[c][0] = mem_speed[c][1] = 2 * mem_spd_multi;
	for (c = 0x3800; c < 0x4000; c++)
		mem_speed[c][0] = mem_speed[c][1] = 4 * mem_spd_multi;
	mem_romspeed_n = mem_romspeed_s = 4;
	rpclog("Update2: mem=%i,%i\n", mem_speed[0x1800][0], mem_speed[0x1800][1]);
}

void mem_setromspeed(int n, int s)
{
	int c;

	mem_romspeed_n = n;
	mem_romspeed_s = s;

/*        if (cp15_cacheon)
	{
		n -= (n >> 1);
		if (!n) n = 1;
		s -= (s >> 1);
		if (!s) s = 1;
	}*/
	mem_recalc_mem_spd_multi();
	for (c = 0x3800; c < 0x4000; c++)
	{
		mem_speed[c][0] = s * mem_spd_multi;
		mem_speed[c][1] = n * mem_spd_multi;
	}

	rpclog("mem_setromspeed %i %i\n", n, s);
}

void mem_updatetimings()
{
	int c;

	mem_recalc_mem_spd_multi();

	for (c = 0; c < 0x3000; c++)
	{
		mem_speed[c][0] = 1 * mem_spd_multi;
		mem_speed[c][1] = 2 * mem_spd_multi;
	}
	rpclog("Update: mem=%i,%i\n", mem_speed[0x1800][0], mem_speed[0x1800][1]);

	mem_setromspeed(mem_romspeed_n, mem_romspeed_s);
}

void resizemem(int memsize) /*memsize is 4096,8192,16384*/
{
	int c;
	rpclog("resizemem %i\n", memsize);
	free(ram);
	ram=(uint32_t *)malloc(memsize*1024);

	memset(ram,0,memsize*1024);
	realmemsize=memsize;

	resetpagesize(0);

	for (c = 0x3fc0; c < 0x4000; c++) /*Map support ROM at end of address space*/
		memstat[c] = support_rom_enabled ? 0 : 5;
}

void resetpagesize(int pagesize)
{
	int c,d=(realmemsize>>2)-1,e;
//        rpclog("Resetpagesize %i %i %i %04X\n",pagesize,realmemsize,ins,d);
	if (pagesize==3 && realmemsize==2048)
	{
		for (c=0x2000;c<0x3000;c++)
		{
			e=c&1023;
			e=(e&1)|((e&~3)<<1);
			mempoint[c] = ((uint8_t *)&ram[((e & 0x3FF) << 10)]) - (c << 12);
		}
	}
	else if (pagesize==3 && realmemsize==1024)
	{
		for (c=0x2000;c<0x3000;c++)
		{
			e=c&511;
			e=(e&1)|((e&~3)<<1);
			mempoint[c] = ((uint8_t *)&ram[((e & 0x1FF) << 10)]) - (c << 12);
		}
	}
	else if (pagesize==3 && realmemsize==512)
	{
		for (c=0x2000;c<0x3000;c++)
		{
			e=c&255;
			e=(e&1)|((e&~3)<<1);
			mempoint[c] = ((uint8_t *)&ram[((e & 0xFF) << 10)]) - (c << 12);
		}
	}
	else
	{
		if (memsize == 12*1024)
		{
			for (c = 0x2000; c < 0x2c00; c++)
			{
				memstat[c] = 3;
				mempoint[c] = ((uint8_t *)&ram[(c & 0xfff) << 10]) - (c << 12);
			}
			for (c = 0x2c00; c < 0x3000; c++)
				memstat[c] = 0;
		}
		else
		{
			for (c = 0x2000; c < 0x3000; c++)
			{
				mempoint[c] = ((uint8_t *)&ram[(c & d) << 10]) - (c << 12);
				memstat[c] = 3;
			}
		}
	}
}

uint32_t readmemf(uint32_t a)
{
	a&=0x3FFFFFC;
//        if (a&0xFC000000) { rpclog("Databort readmemf %08X\n",a); databort=2; return 0xdeadbeef; }
	switch (a>>20)
	{
//#if 0
		case 0x00: case 0x01: case 0x02: case 0x03: /*RAM*/
		case 0x04: case 0x05: case 0x06: case 0x07:
		case 0x08: case 0x09: case 0x0A: case 0x0B:
		case 0x0C: case 0x0D: case 0x0E: case 0x0F:
		case 0x10: case 0x11: case 0x12: case 0x13:
		case 0x14: case 0x15: case 0x16: case 0x17:
		case 0x18: case 0x19: case 0x1A: case 0x1B:
		case 0x1C: case 0x1D: case 0x1E: case 0x1F:
		prefabort_next=1;
		return 0;
		case 0x3F:
			return 0xFFFFFFFF;
//#endif
	}
	prefabort_next=1;
	rpclog("Prefabort %08X\n",a);
	return 0xdeadbeef;
/*        sprintf(err2,"Bad fetch %06X %03X %04X\n",a,a>>15,a&0x7FFF);
	MessageBox(NULL,err2,"Arc",MB_OK);
	dumpregs();
	exit(-1);*/
}

uint8_t readmemfb(uint32_t a)
{
//        if (a==0x1800F42)
/*        if (a==(0x1801010))
	{
		rpclog("Read byte %08X %07X\n",a,PC);
		return mempointb[((a)>>15)&0x7FF][((a)&0x7FFF)];
	}*/
//        if (((a)&~3)==0x2D8D0)
/*        if (a==0x7DC)
	{
		if (!olog) olog=fopen("olog.txt","wt");
		sprintf(err2,"Read byte %08X %07X\n",a,PC);
		fputs(err2,olog);
		return mempointb[((a)>>15)&0x7FF][((a)&0x7FFF)];
	}*/
/*        if (((a)&~0x7FFF)==0x8000)
	{
		rpclog("Read byte %08X %07X %02X  R2=%08X R4=%08X R5=%08X\n",a,PC,mempointb[((a)>>15)&0x7FF][((a)&0x7FFF)],armregs[2],armregs[4],armregs[5]);
		return mempointb[((a)>>15)&0x7FF][((a)&0x7FFF)];
	}*/
	a &= 0x3ffffff;
/*        if ((a&~0xFFF)==0x8000)
	{
		printf("Read %04X %08X %02X\n",a,PC,mempointb[((a)>>15)&0x7FF][(a)&0x7FFF]);
		return mempointb[((a)>>15)&0x7FF][(a)&0x7FFF];
	}*/

	switch (a>>20)
	{
		/*Unmapped physical RAM (A540 only)*/
		case 0x20: case 0x21: case 0x22: case 0x23:
		case 0x24: case 0x25: case 0x26: case 0x27:
		case 0x28: case 0x29: case 0x2a: case 0x2b:
		case 0x2c: case 0x2d: case 0x2e: case 0x2f:
		if (memmode != MEMMODE_SUPER)
			goto data_abort;
		return 0xff;

		case 0x30:
		case 0x31:
		case 0x32: /*IOC*/
		case 0x33:
		
		if (memmode != MEMMODE_SUPER)
			goto data_abort;

		if (!(a & ((1 << 16) | (1 << 17) | (1 << 21)))) /*MEMC podule space*/
			return podule_memc_read_b((a & 0xc000) >> 14, a & 0x3fff);

		if (fdctype == FDC_82C711 && a >= 0x3012000 && a <= 0x302A000)
			return c82c711_fdc_dmaread(a == 0x302A000, NULL);

		bank=(a>>16)&7;

		switch (bank)
		{
			case 0: /*IOC*/
			if (a & (1 << 21))
				return ioc_read(a);
			return 0xff;
			case 1: /*1772 FDC*/
			if (fdctype != FDC_82C711)
				return wd1770_read(a);
			return c82c711_read(a);
			case 2: /*Econet*/
			if (machine_type == MACHINE_TYPE_A4 && (a & 0xc000) == 0xc000)
				return lc_read(a);
			if (joystick_rtfm_present)
				return joystick_rtfm_read(a);
			return 0xFF;
			case 3: /*Serial*/
				return serial_read(a);
			case 4: /*Internal podules*/
/*                        if (romset>3)
			{
				if ((a&~0x1F)==0x33c0004) return readeterna(a);
				if ((a&~0x1F)==0x3340000) return readeterna(a);
				if ((a&~0x1F)==0x33C0000) return readeterna(a);
			}*/
			return podule_read_b((a & 0xC000) >> 14, a & 0x3FFF);
			case 5:
			if (fdctype == FDC_82C711) /*IOEB*/
			{
				return ioeb_read(a);
			}
			else /*Internal latches*/
			{
				switch (a&0xFFFC)
				{
					case 0x0010: return 0xFF; /*Printer*/
					case 0x0018:
					return 0xFF; /*FDC Latch B*/
					case 0x0008: case 0x000C:
					case 0x0020: case 0x0024: case 0x0028: case 0x002C:
					if (st506_present)
						return st506_internal_readb(a);
					return 0xFF;
					case 0x0040: /*FDC Latch A*/
					return 0xFF;
					case 0x0048: return 0xFF; /*????*/
					case 0x0050: return 0;
					case 0x0074: return 0xFF; /*????*/
				}
			}
			case 6: /*Backplane*/
			switch (a&0xFFFC)
			{
				case 0x0000:
				return podule_irq_state();

				case 0x0004:
				return podule_read_backplane_mask();
			}
			break;
		}
		return 0xFF;

		case 0x34: case 0x35: case 0x36: case 0x37: /*Expansion ROMs*/
		if ((a & 3) == 3)
			return rom_5th_column[(a >> 2) & 0x1ffff];
		return 0xff;

		case 0x3f: /*Expansion ROMs*/
		if (!support_rom_enabled)
			break;
		if ((a & 3) == 3)
			return rom_arcrom[(a >> 2) & 0xffff];
		return 0xff;
	}
//        rpclog("Data abort b %07X\n",a);
data_abort:
	databort=1;
	LOG_DATABORT("Dat abort readb %07X %07X\n",a,PC);
	return 0xef;
/*        sprintf(err2,"Bad read byte %06X %03X %04X\n",a,a>>15,a&0x7FFF);
	MessageBox(NULL,err2,"Arc",MB_OK);
	dumpregs();
	exit(-1);*/
}

uint32_t readmemfl(uint32_t a)
{
//        uint32_t temp;
/*        if (a==0x7DC)
	{
		if (!olog) olog=fopen("olog.txt","wt");
		sprintf(err2,"Read word %08X %07X\n",a,PC);
		fputs(err2,olog);
		return mempointb[((a)>>15)&0x7FF][((a)&0x7FFF)];
	}*/
/*        if (((a)&~0x7FFF)==0x8000)
	{
		rpclog("Read long %08X %07X %08X R2=%08X R4=%08X R5=%08X\n",a,PC,mempoint[((a)>>15)&0x7FF][((a)&0x7FFF)>>2],armregs[2],armregs[4],armregs[5]);
		return mempoint[((a)>>15)&0x7FF][((a)&0x7FFF)>>2];
	}*/
	a &= 0x3ffffff;

	switch (a>>20)
	{
#if 0
		case 0x00: case 0x01: case 0x02: case 0x03: /*RAM*/
		case 0x04: case 0x05: case 0x06: case 0x07:
		case 0x08: case 0x09: case 0x0A: case 0x0B:
		case 0x0C: case 0x0D: case 0x0E: case 0x0F:
		case 0x10: case 0x11: case 0x12: case 0x13:
		case 0x14: case 0x15: case 0x16: case 0x17:
		case 0x18: case 0x19: case 0x1A: case 0x1B:
		case 0x1C: case 0x1D: case 0x1E: case 0x1F:
		databort=1;
		return 0xdeadbeef;
#endif

		/*Unmapped physical RAM (A540 only)*/
		case 0x20: case 0x21: case 0x22: case 0x23:
		case 0x24: case 0x25: case 0x26: case 0x27:
		case 0x28: case 0x29: case 0x2a: case 0x2b:
		case 0x2c: case 0x2d: case 0x2e: case 0x2f:
		if (memmode != MEMMODE_SUPER)
			goto data_abort;
		return 0xffffffff;

		case 0x30:
		case 0x31:
		case 0x32: /*IOC*/
		case 0x33:
		
		if (memmode != MEMMODE_SUPER)
			goto data_abort;

		if (!(a & ((1 << 16) | (1 << 17) | (1 << 21)))) /*MEMC podule space*/
			return podule_memc_read_w((a & 0xc000) >> 14, a & 0x3fff);

		if (fdctype == FDC_82C711 && a >= 0x3012000 && a <= 0x302A000)
			return c82c711_fdc_dmaread(a == 0x302A000, NULL);

//                        if (output) rpclog("IOC space readl %08X\n",a);
		bank=(a>>16)&7;
		switch (bank)
		{
			case 0: /*IOC*/
			if (a & (1 << 21))
				return ioc_read(a);
			return 0xff;
			case 1: /*1772 FDC*/
			if (fdctype != FDC_82C711)
				return wd1770_read(a);
			if ((a&0xFFF)==0x7C0)
				return readidew(&ide_internal);
			return c82c711_read(a);
			case 2: /*Econet*/
			if (machine_type == MACHINE_TYPE_A4 && (a & 0xc000) == 0xc000)
				return lc_read(a);
			if (joystick_rtfm_present)
				return joystick_rtfm_read(a);
			return 0xFFFF;
			case 3: /*Serial*/
				return serial_read(a);
			case 4: /*Internal podules*/
/*                        if (romset>3)
			{
				if ((a&~0x1F)==0x33c0004) return readeterna(a);
				if ((a&~0x1F)==0x3340000) return readeterna(a);
				if ((a&~0x1F)==0x33C0000) return readeterna(a);
			}*/
			return podule_read_w((a & 0xC000) >> 14, a & 0x3FFF);
			case 5: /*IOEB*/
			if (fdctype == FDC_82C711)
			{
				return ioeb_read(a);
			}
			else /*Internal latches*/
			{
				switch (a&0xFFFC)
				{
					case 0x0010: return 0xFFFF; /*Printer*/
					case 0x0018:
					return 0xFFFF; /*FDC Latch B*/
					case 0x0008: case 0x000C:
					case 0x0020: case 0x0024: case 0x0028: case 0x002C:
					if (st506_present)
						return st506_internal_readl(a);
					return 0xFFFFFFFF;
					case 0x0040: /*FDC Latch A*/
					return 0xFFFF;
					case 0x0048: return 0xFFFF; /*????*/
					case 0x0050: return 0;
					case 0x0074: return 0xFFFF; /*????*/
					case 0x0078: return 0xFFFF; /*????*/
				}
			}
			break;
			case 6: /*Backplane*/
			switch (a&0xFFFC)
			{
				case 0x0000:
				return podule_irq_state();

				case 0x0004:
				return podule_read_backplane_mask();
			}
			break;
		}
		return 0xFFFF;
		case 0x34: case 0x35: case 0x36: case 0x37: /*Expansion ROMs*/
		return (rom_5th_column[(a >> 2) & 0x1ffff] << 24) | 0xffffff;

		case 0x3f: /*Expansion ROMs*/
		if (!support_rom_enabled)
			break;
		return (rom_arcrom[(a >> 2) & 0xffff] << 24) | 0xffffff;
	}
//        rpclog("Data abort l %07X\n",a);
data_abort:
	databort=1;
	LOG_DATABORT("Dat abort readl %07X %07X\n",a,PC);
	return 0xdeadbeef;
/*        sprintf(err2,"Bad read long %06X %03X %04X\n",a,a>>15,a&0x7FFF);
	MessageBox(NULL,err2,"Arc",MB_OK);
	dumpregs();
	exit(-1);*/
}

uint32_t readmemf_debug(uint32_t a)
{
	a &= 0x3FFFFFC;

	if (mempoint[a >> 12])
		return *(uint32_t *)&mempoint[a >> 12][a];

	return 0xffffffff;
}

void writememfb_debug(uint32_t a, uint8_t v)
{
	a &= 0x3FFFFFF;

	if (mempoint[a >> 12])
		mempoint[a >> 12][a] = v;
}
void writememfl_debug(uint32_t a, uint32_t v)
{
	a &= 0x3FFFFFC;

	if (mempoint[a >> 12])
		*(uint32_t *)&mempoint[a >> 12][a] = v;
}

int f42count=0;

void writememfb(uint32_t a,uint8_t v)
{
	int bank;

	a &= 0x3ffffff;

	switch (a>>20)
	{
#if 0
		case 0x00: case 0x01: case 0x02: case 0x03: /*RAM*/
		case 0x04: case 0x05: case 0x06: case 0x07:
		case 0x08: case 0x09: case 0x0A: case 0x0B:
		case 0x0C: case 0x0D: case 0x0E: case 0x0F:
		case 0x10: case 0x11: case 0x12: case 0x13:
		case 0x14: case 0x15: case 0x16: case 0x17:
		case 0x18: case 0x19: case 0x1A: case 0x1B:
		case 0x1C: case 0x1D: case 0x1E: case 0x1F:
		databort=1;
		return;
#endif
//                case 0x1F: return; if (a>=0x1f08000 && a<=0x1f0ffff) return; break;

		/*Unmapped physical RAM (A540 only)*/
		case 0x20: case 0x21: case 0x22: case 0x23:
		case 0x24: case 0x25: case 0x26: case 0x27:
		case 0x28: case 0x29: case 0x2a: case 0x2b:
		case 0x2c: case 0x2d: case 0x2e: case 0x2f:
		if (memmode != MEMMODE_SUPER)
			goto data_abort;
		return;

		case 0x30:
		case 0x31:
		case 0x32: /*IOC*/
		case 0x33:
		
		if (memmode != MEMMODE_SUPER)
			goto data_abort;

		if (!(a & ((1 << 16) | (1 << 17) | (1 << 21)))) /*MEMC podule space*/
		{
			podule_memc_write_b((a & 0xc000) >> 14, a & 0x3fff, v);
			return;
		}

		if (fdctype == FDC_82C711 && a >= 0x3012000 && a <= 0x302A000)
		{
			c82c711_fdc_dmawrite(v, (a == 0x302A000), NULL);
			return;
		}

//                rpclog("IOC space writeb %08X %02X\n",a,v);
		bank=(a>>16)&7;
		switch (bank)
		{
			case 0: /*IOC*/
			if (a & (1 << 21))
				ioc_write(a, v);
			return;
			case 1: /*1772 FDC*/
			if (fdctype != FDC_82C711)
				wd1770_write(a,v);
			else
				c82c711_write(a,v);
			return;
			case 2: /*Econet*/
			if (machine_type == MACHINE_TYPE_A4 && (a & 0xc000) == 0xc000)
			{
				lc_write(a,v);
				return;
			}
			return;
			case 3: /*Serial*/
			serial_write(a, v);
			return;
			case 4: /*Internal podules*/
/*                        if (romset>3)
			{
				if ((a&~0x1F)==0x33c0004) { writeeterna(a,v); return; }
				if ((a&~0x1F)==0x3340000) { writeeterna(a,v); return; }
				if ((a&~0x1F)==0x33C0000) { writeeterna(a,v); return; }
			}*/
			podule_write_b((a & 0xC000) >> 14, a & 0x3FFF, v);
			return;
			case 5: /*IOEB*/
			if (fdctype == FDC_82C711)
			{
				ioeb_write(a, v);
			}
			else /*Internal latches*/
			{
				switch (a&0xFFFC)
				{
					case 0x0000: case 0x0004: case 0x0008: case 0x000C:
					case 0x0028: case 0x002C:
					if (st506_present)
						st506_internal_writeb(a, v);
					return;
					case 0x0010: /*Printer*/
					printer_data_write(v);
					return;
					case 0x0018:
					wd1770_writelatch_b(v);
					return; /*FDC Latch B*/
					case 0x0040: /*FDC Latch A*/
					wd1770_writelatch_a(v);
					return;
					case 0x0048: /*Video clock (A540)*/
					vidc_setclock(v & 3);
					return;
				}
			}
			break;
			case 6: /*Backplane*/
			if (fdctype == FDC_WD1793_A500)
			{
				wd1770_writelatch_a(v);
			}
			else
			{
				switch (a&0xFFFC)
				{
					case 0x0000:
					return;
					case 0x0004:
					podule_write_backplane_mask(v);
					return;
				}
			}
			break;
		}
		return;
	}

data_abort:
	LOG_DATABORT("Dat abort writeb %07X %07X %08X %i %i\n",a,PC, memstat[((a)>>12)&0x3FFF], modepritablew[memmode][memstat[((a)>>12)&0x3FFF]], modepritablew[memmode][memstat[((a)>>12)&0x3FFF]] && !((a)>>26));
	databort=1;
}

void writememfl(uint32_t a,uint32_t v)
{
	a &= 0x3ffffff;
/*        if (a==(0x1801010))
	{
		rpclog("Writel R12+284 %07X %08X %08X\n",PC,v,a);
		mempoint[((a)>>15)&0x7FF][((a)&0x7FFF)>>2]=v;
		return;
	}*/
/*        if (a==0x1803BEC)
	{
		rpclog("Write 1803BEC %02X %07X %i\n",v,PC,ins);
		mempoint[((a)>>15)&0x7FF][((a)&0x7FFF)>>2]=v;
		return;
	}*/
/*        if ((a<0x2000000) && modepritablew[memmode][memstat[((a)>>15)&0x7FF]])
	{
		sprintf(s,"Write %04X %08X %08X\n",a,v,PC);
		fputs(s,olog);
		mempoint[((a)>>15)&0x7FF][((a)&0x7FFF)>>2]=v;
//                output=1; timetolive=50;
		return;
	}*/

	switch (a>>20)
	{
#if 0
		case 0x00: case 0x01: case 0x02: case 0x03: /*RAM*/
		case 0x04: case 0x05: case 0x06: case 0x07:
		case 0x08: case 0x09: case 0x0A: case 0x0B:
		case 0x0C: case 0x0D: case 0x0E: case 0x0F:
		case 0x10: case 0x11: case 0x12: case 0x13:
		case 0x14: case 0x15: case 0x16: case 0x17:
		case 0x18: case 0x19: case 0x1A: case 0x1B:
		case 0x1C: case 0x1D: case 0x1E: case 0x1F:
		databort=1;
		return;
#endif

		/*Unmapped physical RAM (A540 only)*/
		case 0x20: case 0x21: case 0x22: case 0x23:
		case 0x24: case 0x25: case 0x26: case 0x27:
		case 0x28: case 0x29: case 0x2a: case 0x2b:
		case 0x2c: case 0x2d: case 0x2e: case 0x2f:
		if (memmode != MEMMODE_SUPER)
			goto data_abort;
		return;

		case 0x30:
		case 0x31:
		case 0x32: /*IOC*/
		case 0x33:
		
		if (memmode != MEMMODE_SUPER)
			goto data_abort;

		if (!(a & ((1 << 16) | (1 << 17) | (1 << 21)))) /*MEMC podule space*/
		{
			podule_memc_write_w((a & 0xc000) >> 14, a & 0x3fff, v);
			return;
		}
		if (fdctype == FDC_82C711 && a >= 0x3012000 && a <= 0x302A000)
		{
			c82c711_fdc_dmawrite(v, (a == 0x302A000), NULL);
			return;
		}
//                rpclog("IOC space writel %08X %02X\n",a,v);
		bank=(a>>16)&7;
		switch (bank)
		{
			case 0: /*IOC*/
			if (a & (1 << 21))
				ioc_write(a,v>>16);
			return;
			case 1: /*1772 FDC*/
			if (fdctype != FDC_82C711)
				wd1770_write(a,v>>16);
			else
			{
				if ((a&0xFFF)==0x7C0)
				{
					writeidew(&ide_internal, v >> 16);
					return;
				}
				c82c711_write(a,v);
			}
			return;
			case 2: /*Econet*/
			if (machine_type == MACHINE_TYPE_A4 && (a & 0xc000) == 0xc000)
			{
				lc_write(a,v);
				return;
			}
			return;
			case 3: /*Serial*/
			serial_write(a, v);
			return;
			case 4: /*Internal podules*/
/*                        if (romset>3)
			{
				if ((a&~0x1F)==0x33c0004) { writeeterna(a,v); return; }
				if ((a&~0x1F)==0x3340000) { writeeterna(a,v); return; }
				if ((a&~0x1F)==0x33C0000) { writeeterna(a,v); return; }
			}*/
			podule_write_w((a & 0xC000) >> 14, a & 0x3FFF, v);
			return;
			case 5: /*IOEB*/
			v>>=16;
			if (fdctype == FDC_82C711)
			{
				ioeb_write(a, v);
			}
			else /*Internal latches*/
			{
				switch (a&0xFFFC)
				{
					case 0x0000: case 0x0004: case 0x0008: case 0x000C:
					case 0x0028: case 0x002C:
					if (st506_present)
						st506_internal_writel(a, v);
					return;
					case 0x0010: /*Printer*/
					printer_data_write(v);
					return;
					case 0x0018:
					wd1770_writelatch_b(v);
					return; /*FDC Latch B*/
					case 0x0040: /*FDC Latch A*/
					wd1770_writelatch_a(v);
					return;
					case 0x0048: return; /*????*/
					case 0x0050: return; /*IOEB*/
					case 0x0074: return; /*????*/
					case 0x0078: return; /*????*/
//                                        default: rpclog("Bad 5 writel %08X\n",a);
				}
			}
			break;
			case 6: /*Backplane*/
			switch (a&0xFFFC)
			{
				case 0x0000:
				return;
				case 0x0004:
				podule_write_backplane_mask(v >> 16);
				return;
			}
			break;
		}
		return;
		case 0x34: case 0x35: /*VIDC*/
		if (memmode != MEMMODE_SUPER)
			goto data_abort;

		LOG_VIDC_REGISTERS("Write VIDC %08X %08X %07X %08X\n",a,v,PC,armregs[15]);
		writevidc(v);
		return;
		case 0x36: /*MEMC*/
		if (memmode != MEMMODE_SUPER)
			goto data_abort;

		writememc(a);
		return;
		case 0x38: case 0x39: case 0x3A: case 0x3B: /*CAM*/
		case 0x3C: case 0x3D: case 0x3E: case 0x3F:
		if (memmode != MEMMODE_SUPER)
			goto data_abort;

		writecam(a);
		return;
//                case 0x35: return; /*??? - Fire & Ice writes here*/
	}

data_abort:
	LOG_DATABORT("Dat abort writel %07X %07X\n",a,PC);
	databort=1;
//        rpclog("Dat abort writel %07X %07X\n",a,PC);
/*        sprintf(err2,"Bad write long %06X %03X %04X %08X\n",a,a>>15,a&0x7FFF,v);*/
}

