/* mem.h
 */


#define INCB(b)		(b) = ((b)+1)&0xff;
#define INCW(w)		(w) = ((w)+1)&0xffff;
#define DECB(b)		(b) = ((b)-1)&0xff;
#define DECW(w)		(w) = ((w)-1)&0xffff;
#define ADDB(b,v)	(b) = ((b)+(v))&0xff;
#define ADDW(w,v)	(w) = ((w)+(v))&0xffff;

#define REPLACE_HI(x,v)	(((x)&0xff)|((v)<<8))
#define REPLACE_LO(x,v)	(((x)&0xff00)|(v))

struct memory {
	uint	(*read[256])(uint addr);
        void    (*write[256])(uint addr, uint val);
	byte	*readptr[256];
	byte	*writeptr[256];
};


GLOBAL struct memory mem;


#define MEM_ZREAD(ofs,val)	val = mem.readptr[0][ofs]

#define MEM_ZWRITE(ofs,val) 	mem.write[0](ofs,val)

#define MEM_SREAD(ofs,val) 	val = mem.readptr[1][ofs]

#define MEM_SWRITE(ofs,val) 	mem.write[1](256+(ofs),val)



#if defined(USE_INLINE) || !defined(USE_MACRO)

#define MEM_READ(adr,val) 	val = mem_read(adr);
#define MEM_WRITE(adr,val)	mem_write(adr,val);
#define MEM_WREAD(adr,val)	val = mem_wread(adr);
#define MEM_WREAD_BUG(adr,val)	val = mem_wread_bug(adr);
#define MEM_WWRITE(adr,val)	mem_wwrite(adr,val);
#define MEM_WZREAD(adr,val)	val = mem_wzread(adr);

#if !defined(IS_MAIN) && !defined(USE_INLINE)
extern byte mem_read(uint adr);
extern void mem_write(uint adr, uint val);
extern word mem_wread(uint adr);
extern word mem_wread_bug(uint adr);
extern void mem_wwrite(uint adr, uint val);
extern word mem_wzread(uint adr);
#else

#ifdef USE_INLINE
#define INLINE static inline
#else
#define INLINE
#endif

INLINE byte mem_read(uint adr) {
uint page = HI(adr);	
uint ofs = LO(adr);
byte *bp = mem.readptr[page];	
	if(bp)	
		return bp[ofs];
	else 
		return mem.read[page](WORD(ofs,page)); 	
} 


INLINE void mem_write(uint adr, uint val) {
uint page = HI(adr);						
uint ofs = LO(adr);						
byte *bp = mem.writeptr[page];				
	if(bp)							
		bp[ofs] = val;				
	else							
		mem.write[page](adr,val);			
}


INLINE word mem_wread(uint adr) {					
uint page = HI(adr);						
uint ofs = LO(adr);
byte *bp = mem.readptr[page];
uint val;
	if(bp)							
		val = bp[ofs]; 			
	else 							
		val = mem.read[page](adr); 
	ofs = (ofs+1)&0xff;
	page = (page+!ofs)&0xff;
	adr = (adr+1)&0xffff;
	bp = mem.readptr[page];				
	if(bp)							
		return WORD(val,bp[ofs]);		
	else							
		return WORD(val,mem.read[page](adr));
} 

INLINE word mem_wread_bug(uint adr) {				
uint page = HI(adr);						
uint ofs = LO(adr);						
byte *bp = mem.readptr[page];				
uint val;
	if(bp)						
		val = bp[ofs]; 
	else 				
		val = mem.read[page](adr); 	
	ofs = (ofs+1)&0xff;
	bp = mem.readptr[page];	
	if(bp)				
		return WORD(val,bp[ofs]);		
	else						
		return WORD(val,mem.read[page](WORD(ofs,page)));
} 
	

INLINE void mem_wwrite(uint adr, uint val) {
uint page = HI(adr);			
uint ofs = LO(adr);		
byte *bp = mem.writeptr[page];				
	if(bp)							
		bp[ofs] = LO(val);				
	else							
		mem.write[page](adr,LO(val));			
	ofs = (ofs+1)&0xff;
	page = (page+!ofs)&0xff;
	adr = (adr+1)&0xffff;
	bp = mem.writeptr[page];				
	if(bp)							
		bp[ofs] = HI(val);
	else							
		mem.write[page](adr,HI(val));		
}



INLINE word mem_wzread(uint ofs) {
uint val;
	val = mem.readptr[0][ofs];				
	ofs = (ofs+1)&0xff;
	return WORD(val,mem.readptr[0][ofs]);
}


#endif

#else
/* Macro definitions for all */



#define MEM_READ(adr,val) {					\
byte _page = HI(adr);						\
byte _ofs = LO(adr);						\
byte *_bp = mem.readptr[_page];					\
	if(_bp)							\
		val = _bp[_ofs]; 				\
	else 							\
		val = mem.read[_page](WORD(_ofs,_page)); 	\
} 


#define MEM_WRITE(adr,val) {					\
byte _page = HI(adr);						\
byte _ofs = LO(adr);						\
byte *_bp = mem.writeptr[_page];				\
	if(_bp)							\
		_bp[_ofs] = val;				\
	else							\
		mem.write[_page](adr,val);			\
}


#define MEM_WREAD(adr,val) {					\
byte _page = HI(adr);						\
byte _ofs = LO(adr);						\
byte *_bp = mem.readptr[_page];					\
	if(_bp)							\
		val = _bp[_ofs]; 				\
	else 							\
		val = mem.read[_page](adr); 			\
	_page += !(++_ofs);					\
	_bp = mem.readptr[_page];				\
	if(_bp)							\
		val = WORD(val,_bp[_ofs]);			\
	else							\
		val = WORD(val,mem.read[_page](adr+1));		\
} 

#define MEM_WREAD_BUG(adr,val) {				\
byte _page = HI(adr);						\
byte _ofs = LO(adr);						\
byte *_bp = mem.readptr[_page];					\
	if(_bp)							\
		val = _bp[_ofs]; 				\
	else 							\
		val = mem.read[_page](adr); 			\
	_ofs++;							\
	_bp = mem.readptr[_page];				\
	if(_bp)							\
		val = WORD(val,_bp[_ofs]);			\
	else							\
		val = WORD(val,mem.read[_page](WORD(_ofs,_page)));\
} 
	

#define MEM_WWRITE(adr,val) {					\
byte _page = HI(adr);						\
byte _ofs = LO(adr);						\
byte *_bp = mem.writeptr[_page];				\
	if(_bp)							\
		_bp[_ofs] = LO(val);				\
	else							\
		mem.write[_page](adr,LO(val));			\
	_page += !(++_ofs);					\
	_bp = mem.writeptr[_page];				\
	if(_bp)							\
		_bp[_ofs] = HI(val);				\
	else							\
		mem.write[_page](adr+1,HI(val));		\
}



#define MEM_WZREAD(ofs,val) { 					\
byte _ofs = ofs;						\
	val = mem.readptr[0][_ofs];				\
	_ofs++;							\
	val = WORD(val,mem.readptr[0][_ofs]);			\
}


#endif

