musix 0.3.5

Music player library for esoteric audio formats (music from C64,Amiga etc)
Documentation
/**
 * @ingroup   emu68_lib
 * @file      emu68/mem68.h
 * @author    Benjamin Gerard
 * @date      1999/03/13
 * @brief     68k memory and IO manager header.
 *
 */

/* $Id: mem68.h 121 2009-06-30 17:30:22Z benjihan $ */

/* Copyright (C) 1998-2009 Benjamin Gerard */

#ifndef _EMU68_MEM68_H_
#define _EMU68_MEM68_H_

#include "emu68_api.h"
#include "struct68.h"

/** @defgroup  emu68_lib_mem68  68k memory and IO manager
 *  @ingroup   emu68_lib
 *  @brief     Handling memory and I/O access.
 *
 *   EMU68 memory manager assumes that all addresses in the lowest
 *   half part of address space are memory access. A simple bit test
 *   over most signifiant bit (23) of address allow to choose beetween
 *   memory or eventual IO access. In case of memory access, address
 *   is masked to fit available 68K onboard memory. Overflow does NOT
 *   generate address error.  IO access are performed towards quick
 *   access tables. There are 6 acccess tables: for each read and
 *   write access in 3 sizes (byte, word and long).  Each of this 6
 *   tables has 256 entries filled with a pointer to suitable
 *   function. At init time, the entries of all tables are initialized
 *   to access 68K onboard memory. When an IO is plugged by user, it
 *   is mapped somewhere in 68K address space. EMU68 memory manager
 *   get bit 8 to 15 of address to make an index to be used in the
 *   suitable table (R/W for B/W/L).
 *
 *   Featuring :
 *   - Onboard memory byte, word and long read/write access.
 *   - Optimized IO warm mapping/unmapping.
 *   - Optionnal (compile time) enhanced memory control with RWX access
 *     tag and hardware breakpoints.
 *
 *   Limitations :
 *   - For optimization purposes IO must be mapped in high half memory
 *     (bit 23 of address setted).
 *   - Two IO can not shared the same memory location for bit 8 to 15.
 *     Conflicts could be resolved by creating an intermediate IO which
 *     dispatches to others. This mechanism has not been implemented yet,
 *     so users must do it themself if needed.
 *
 *   Atari-ST & Amiga IO areas :
 *   - @p  FF8800-FF88FF : YM2149 (ST)
 *   - @p  FF8900-FF89FF : Micro-Wire (STE)
 *   - @p  FF8200-FF82FF : Shifter (ST)
 *   - @p  FFFA00-FFFAFF : MFP (ST)
 *   - @p  DFF000-DFF0DF : Paula (AMIGA)
 *
 * @{
 */

/** Memory access flags for emu68_t::chk (debug mode only). */
enum {
  EMU68_R = 0x01,  /**< Memory location has been read           */
  EMU68_W = 0x02,  /**< Memory location has been written        */
  EMU68_X = 0x04,  /**< Memory location has been executed       */
  EMU68_B = 0x08,  /**< Memory location has emulator-breakpoint */
  EMU68_M = 0xF0   /**< Breakpoint number                       */
};

/** @name  Memory/IO quick access tables.
 *  @{
 */


/** @} */

/** @name Effective address calculation tables.
 *
 *   The get_ab[bwl] tables are used by EMU68 to calculate operand
 *   effective address. Each of them is indexed by operand addressing
 *   mode. Each entry is a pointer to a function which do everything
 *   neccessary to update processor state (e.g. address register
 *   increment or decrement). reg parameter is register number coded
 *   in the three first bit (0 to 2) of 68k opcode. When the mode is
 *   7, register parameter is used as an index in a second level
 *   function table for extended addressing mode.
 *
 * @{
 */

EMU68_EXTERN
/** Byte operand effective address calculation function table. */
addr68_t (*const get_eab68[8])(emu68_t * const,int reg);

EMU68_EXTERN
/** Word operand effective address calculation function table. */
addr68_t (*const get_eaw68[8])(emu68_t * const,int reg);

EMU68_EXTERN
/** Long operand effective address calculation function table. */
addr68_t (*const get_eal68[8])(emu68_t * const,int reg);


#define get_EAB(MODE,REG) get_eab68[MODE](emu68,REG)
#define get_EAW(MODE,REG) get_eaw68[MODE](emu68,REG)
#define get_EAL(MODE,REG) get_eal68[MODE](emu68,REG)


/** @name  68K onboard memory access.
 *  @{
 */

EMU68_EXTERN
/** Read memory byte */
void mem68_read_b(emu68_t * const emu68);

EMU68_EXTERN
/** Read memory word */
void mem68_read_w(emu68_t * const emu68);

EMU68_EXTERN
/** Read memory long */
void mem68_read_l(emu68_t * const emu68);

EMU68_EXTERN
/** Write memory byte */
void mem68_write_b(emu68_t * const emu68);

EMU68_EXTERN
/** Write memory word */
void mem68_write_w(emu68_t * const emu68);

EMU68_EXTERN
/** Write memory long */
void mem68_write_l(emu68_t * const emu68);

static inline uint68_t _read_B(emu68_t * const emu68,
                               const addr68_t addr)
{
  emu68->bus_addr = addr;
  mem68_read_b(emu68);
  return (u8) emu68->bus_data;
}

static inline uint68_t _read_EAB(emu68_t * const emu68,
                                 const int mode, const int reg)
{
  emu68->bus_addr = get_eab68[mode](emu68,reg);
  mem68_read_b(emu68);
  return (u8) emu68->bus_data;
}


static inline uint68_t _read_W(emu68_t * const emu68,
                               const addr68_t addr)
{
  emu68->bus_addr = addr;
  mem68_read_w(emu68);
  return (u16) emu68->bus_data;
}

static inline uint68_t _read_EAW(emu68_t * const emu68,
                                 const int mode, const int reg)
{
  emu68->bus_addr = get_eaw68[mode](emu68,reg);
  mem68_read_w(emu68);
  return (u16) emu68->bus_data;
}


static inline uint68_t _read_L(emu68_t * const emu68,
                               const addr68_t addr)
{
  emu68->bus_addr = addr;
  mem68_read_l(emu68);
  return (u32) emu68->bus_data;
}

static inline uint68_t _read_EAL(emu68_t * const emu68,
                                 const int mode, const int reg)
{
  emu68->bus_addr = get_eal68[mode](emu68,reg);
  mem68_read_l(emu68);
  return (u32) emu68->bus_data;
}

/** Read memory byte. */
#define read_B(ADDR) _read_B(emu68,(ADDR))

/** Read memory word. */
#define read_W(ADDR) _read_W(emu68,(ADDR))

/** Read memory long. */
#define read_L(ADDR) _read_L(emu68,(ADDR))

/** Read memory byte from AE mode. */
#define read_EAB(MODE,PARM) _read_EAB(emu68,(MODE),(PARM))

/** Read memory word from AE mode. */
#define read_EAW(MODE,PARM) _read_EAW(emu68,(MODE),(PARM))

/** Read memory long from AE mode. */
#define read_EAL(MODE,PARM) _read_EAL(emu68,(MODE),(PARM))

static inline void _write_B(emu68_t * const emu68,
                            const addr68_t addr, const int68_t v)
{
  emu68->bus_addr = addr;
  emu68->bus_data = v;
  mem68_write_b(emu68);
}

static inline void _write_EAB(emu68_t * const emu68,
                              const int mode, const int reg, const int68_t v)
{
  emu68->bus_addr = get_eab68[mode](emu68,reg);
  emu68->bus_data = v;
  mem68_write_b(emu68);
}


static inline void _write_W(emu68_t * const emu68, addr68_t addr, int68_t v)
{
  emu68->bus_addr = addr;
  emu68->bus_data = v;
  mem68_write_w(emu68);
}

static inline void _write_EAW(emu68_t * const emu68,
                              const int mode, const int reg, const int68_t v)
{
  emu68->bus_addr = get_eaw68[mode](emu68,reg);
  emu68->bus_data = v;
  mem68_write_w(emu68);
}


static inline void _write_L(emu68_t * const emu68, addr68_t addr, int68_t v)
{
  emu68->bus_addr = addr;
  emu68->bus_data = v;
  mem68_write_l(emu68);
}

static inline void _write_EAL(emu68_t * const emu68,
                              const int mode, const int reg, const int68_t v)
{
  emu68->bus_addr = get_eal68[mode](emu68,reg);
  emu68->bus_data = v;
  mem68_write_l(emu68);
}


/** Write memory byte */
#define write_B(ADDR,V) _write_B(emu68,(ADDR),(V))

/** Write memory word */
#define write_W(ADDR,V) _write_W(emu68,(ADDR),(V))

/** Write memory long */
#define write_L(ADDR,V) _write_L(emu68,(ADDR),(V))

/** Write memory byte at EA mode */
#define write_EAB(MODE,PARM,V) _write_EAB(emu68,(MODE),(PARM),(V))

/** Write memory word at EA mode */
#define write_EAW(MODE,PARM,V) _write_EAW(emu68,(MODE),(PARM),(V))

/** Write memory long at EA mode */
#define write_EAL(MODE,PARM,V) _write_EAL(emu68,(MODE),(PARM),(V))

/** @} */


/** @name Instruction read.
 *  @{
 */
EMU68_EXTERN
int68_t mem68_nextw(emu68_t * emu68);  /**< Decode word and update PC */
EMU68_EXTERN
int68_t mem68_nextl(emu68_t * emu68);  /**< Decode long and update PC */

/** mem68_nextw() convenience macro */
#define get_nextw() mem68_nextw(emu68)
/** mem68_nextl() convenience macro */
#define get_nextl() mem68_nextl(emu68)

/** @} */


/** @name Stack access.
 *  @{
 */
EMU68_EXTERN void mem68_pushl(emu68_t * emu68, int68_t v);  /**< Push long */
EMU68_EXTERN void mem68_pushw(emu68_t * emu68, int68_t v);  /**< Push word */
EMU68_EXTERN int68_t mem68_popl(emu68_t * emu68);           /**< Pop long  */
EMU68_EXTERN int68_t mem68_popw(emu68_t * emu68);           /**< Pop word  */

/** mem68_pushl() convenience macro */
#define pushl(V) mem68_pushl(emu68,(V));
/** mem68_pushw() convenience macro */
#define pushw(V) mem68_pushw(emu68,(V));
/** mem68_popl() convenience macro */
#define popl() mem68_popl(emu68);
/** mem68_popw() convenience macro */
#define popw() mem68_popw(emu68);

/** @} */

EMU68_EXTERN
/** Init memory quick access table.
 *
 *    The emu68_mem_init() function must be call at init time.
 *    Currently this function only call the emu68_mem_reset()
 *    function.
 *
 *  @see emu68_mem_reset()
 */
void emu68_mem_init(emu68_t * const emu68);

EMU68_EXTERN
/** Reset memory quick access table.
 *
 *    The emu68_mem_reset() function restores all memory access to
 *    default. All mapped IO will be discard and replace by onboard
 *    memory access.
 */
void emu68_mem_reset(emu68_t * const emu68);

EMU68_EXTERN
/** Add a new memory access control area (for new IO).
 *
 *  @param  area      Which area (bit 16 to 23 of address) to change.
 *  @param  read_bwl  Read function table (byte, word and long in this order)
 *  @param  write_bwl idem read_bwl for write access.
 *
 * @see emu68_mem_reset_area()
 */
void emu68_mem_new_area(emu68_t * const emu68, u8 area,
                        memfunc68_t *read_bwl,
                        memfunc68_t *write_bwl);

EMU68_EXTERN
/** Reset memory access control area to default state.
 *
 * @see emu68_mem_new_area()
 */
void emu68_mem_reset_area(emu68_t * const emu68, u8 area);

/**
 *  @}
 */

#endif /* #ifndef _EMU68_MEM68_H_ */