 /* 
  * UAE - The Un*x Amiga Emulator
  * 
  * memory management
  * 
  * Copyright 1995 Bernd Schmidt
  */

#define kickmem_size 0x080000

#define chipmem_start 0x000000
#define bogomem_start 0xC00000 
#define kickmem_start 0xF80000

extern int ersatzkickfile;

extern char *address_space, *good_address_map;

typedef ULONG (*lget_afunc)(CPTR) REGPARAM;
typedef UWORD (*wget_afunc)(CPTR) REGPARAM;
typedef ULONG (*lget_func)(CPTR) REGPARAM;
typedef UWORD (*wget_func)(CPTR) REGPARAM;
typedef UBYTE (*bget_func)(CPTR) REGPARAM;
typedef void (*lput_func)(CPTR,ULONG) REGPARAM;
typedef void (*wput_func)(CPTR,UWORD) REGPARAM;
typedef void (*bput_func)(CPTR,UBYTE) REGPARAM;
typedef UBYTE *(*xlate_func)(CPTR) REGPARAM;
typedef int (*check_func)(CPTR, ULONG) REGPARAM;

typedef struct {
    /* These ones should be self-explanatory... */
    lget_afunc alget;
    wget_afunc awget;
    lget_func lget;
    wget_func wget;
    bget_func bget;
    lput_func lput;
    wput_func wput;
    bput_func bput;
    /* Use xlateaddr to translate an Amiga address to a UWORD * that can
     * be used to address memory without calling the wget/wput functions. 
     * This doesn't work for all memory banks, so this function may call
     * abort(). */
    xlate_func xlateaddr;
    /* To prevent calls to abort(), use check before calling xlateaddr.
     * It checks not only that the memory bank can do xlateaddr, but also
     * that the pointer points to an area of at least the specified size. 
     * This is used for example to translate bitplane pointers in custom.c */
    check_func check;
} addrbank;

extern addrbank chipmem_bank;
extern addrbank kickmem_bank;
extern addrbank custom_bank;
extern addrbank clock_bank;
extern addrbank cia_bank;
extern addrbank rtarea_bank;
extern addrbank expamem_bank;
extern addrbank fastmem_bank;

extern void rtarea_init (void);
extern void expamem_init (void);
extern void expamem_reset (void);

extern ULONG fastmem_size, chipmem_size, bogomem_size;


/* Default memory access functions */

extern int default_check(CPTR addr, ULONG size) REGPARAM;
extern UBYTE *default_xlate(CPTR addr) REGPARAM;
extern UWORD default_awget(CPTR addr) REGPARAM;
extern ULONG default_alget(CPTR addr) REGPARAM;

extern addrbank membanks[65536];
static __inline__ unsigned int bankindex(CPTR a)
{
    return a>>16;
}

static __inline__ ULONG alongget(CPTR addr)
{
    return membanks[bankindex(addr)].alget(addr);
}
static __inline__ UWORD awordget(CPTR addr)
{
    return membanks[bankindex(addr)].awget(addr);
}
static __inline__ ULONG longget(CPTR addr)
{
    return membanks[bankindex(addr)].lget(addr);
}
static __inline__ UWORD wordget(CPTR addr)
{
    return membanks[bankindex(addr)].wget(addr);
}
static __inline__ UBYTE byteget(CPTR addr) 
{
    return membanks[bankindex(addr)].bget(addr);
}
static __inline__ void longput(CPTR addr, ULONG l)
{
    membanks[bankindex(addr)].lput(addr, l);
}
static __inline__ void wordput(CPTR addr, UWORD w)
{
    membanks[bankindex(addr)].wput(addr, w);
}
static __inline__ void byteput(CPTR addr, UBYTE b)
{
    membanks[bankindex(addr)].bput(addr, b);
}

static __inline__ int check_addr(CPTR a)
{
#if defined(NO_EXCEPTION_3) || CPU_LEVEL > 1
    return 1;
#else
    return (a & 1) == 0;
#endif
}
extern int buserr;
    
extern void memory_init(void);    
extern void map_banks(addrbank *bank, int first, int count);
    
static __inline__ ULONG get_along(CPTR addr) 
{
    if (check_addr(addr))
	return longget(addr);
    buserr = 1;
    return 0;
}
static __inline__ UWORD get_aword(CPTR addr) 
{
    if (check_addr(addr))
	return wordget(addr);
    buserr = 1;
    return 0;
}
static __inline__ ULONG get_long(CPTR addr) 
{
    if (check_addr(addr))
	return longget(addr);
    buserr = 1;
    return 0;
}
static __inline__ UWORD get_word(CPTR addr) 
{
    if (check_addr(addr))
	return wordget(addr);
    buserr = 1;
    return 0;
}
static __inline__ UBYTE get_byte(CPTR addr) 
{
    return byteget(addr); 
}
static __inline__ void put_long(CPTR addr, ULONG l) 
{
    if (!check_addr(addr))
	buserr = 1;
    longput(addr, l);
}
static __inline__ void put_word(CPTR addr, UWORD w) 
{
    if (!check_addr(addr))
	buserr = 1;
    wordput(addr, w);
}
static __inline__ void put_byte(CPTR addr, UBYTE b) 
{
    byteput(addr, b);
}

static __inline__ UBYTE *get_real_address(CPTR addr)
{
    return membanks[bankindex(addr)].xlateaddr(addr);
}

static __inline__ int valid_address(CPTR addr, ULONG size)
{
    return membanks[bankindex(addr)].check(addr, size);
}
