/*
 * Memory emulation classes
 */

#ifndef MEMEMUL_H
#define MEMEMUL_H

#include "types.h"
#include "ulist.h"

#include "dlc/dlc_base.h"
#include "CompEmul.h"
#include "CPUEmul.h"
#include "Registry.h"

class MemEmul;

// A generic memory-mapped IO device
class MMIO_Dev: public DLC_BASE
{
protected:
	struct
	{
		int mask, value;	// defaults only
		int reg_mask;
	} addr;
	
	void SignalIRQ (int queue_anyway = 0) { cur_model->cpu->SignalIRQ (queue_anyway); }
	void ClearIRQ (int queue_anyway_id = 0) { cur_model->cpu->ClearIRQ (queue_anyway_id); }
	void SignalNMI (void) { cur_model->cpu->SignalNMI (); }
	virtual void SignalInt (void);
	virtual void ClearInt (void);
	
	UList<MemEmul *> mememuls;
	friend class MemEmul;

public:
	MMIO_Dev (int m, int v)		// addr.reg_mask is set by the specific
					// device
		{ addr.mask = m; addr.value = v;
		  flags = 0; }
	virtual ~MMIO_Dev (void);
	
	virtual void AddOK (void);
	virtual void RemoveOK (void);
	
	virtual byte MMIO_Read (int addr) = 0;
	virtual void MMIO_Write (int addr, byte val) = 0;
	virtual void Reset (void);
	virtual void Break (void);
	
	virtual void DoTicks (int ticks);
	
	int flags;
#define MMIO_IS_TICKER 1

#define MMIO_IS_ACORNTUBE 0x1000
};

#define MAX_MMIO 50

class MemEmul
{
protected:
	/* Main memory */
	byte coremem[0x10000];
	int displaymem_begin;
	byte display[0x3000];
	
	/* Sideways ram/rom flags */
	int cur_swbank;
	int cur_sw_rdonly;
	int cur_sw_mod;		// Has it been modified yet?
	
	int swbank_rdonly[16];
	byte swbanks[16][0x4000];
	
	/* Memory-mapped IO devices */
	struct mmio_tbl
	{
		int reg;
		MMIO_Dev *dev;
	} mmio_tbl[0xff00-0xfc00];
	// We use an array for speed
	UList<MMIO_Dev *> mmio;
	
	friend class CompEmul;
	
	virtual byte Read_MMIO (int addr);
	virtual void OtherWrite (int addr, byte val);

public:
	MemEmul (void);
	virtual ~MemEmul (void);
	
	inline byte Read (int addr);
	byte ReadSimple (int addr) { return coremem[addr]; }
	inline void Write (int addr, byte val);
	void WriteSimple (int addr, byte val) { coremem[addr] = val; }
	
	virtual void AddDev (MMIO_Dev *d, int addr = -1, int mask = -1);
	virtual void RemoveDev (MMIO_Dev *d);
	
	virtual void ReadROM (int slot, char *fname);
	virtual void SetSW (int slot, int rw);
	virtual void Switch_SWbank (int bank);
	
	void SetDisplayBegin (int addr) { displaymem_begin = addr; }
};

byte MemEmul::Read (int addr)
{
	if (addr < 0xfc00 || addr >= 0xff00)
		return coremem[addr];
	else
		return Read_MMIO (addr);
}

void MemEmul::Write (int addr, byte val)
{
	if (addr < 0x8000)
	{
		if (addr >= displaymem_begin)
			display[addr - displaymem_begin] = 1;
		coremem[addr] = val;
	}
	else
		OtherWrite (addr, val);
}

#endif /* MEMEMUL_H */

/* End of file. */
