// // Core functionality // //! \file tonc_core.h //! \author J Vijn //! \date 20060508 - 20080128 // /* === NOTES === * Contents: bits, random, dma, timer * 20080129,jv: added tonccpy/set routines. */ #ifndef TONC_CORE #define TONC_CORE #include "tonc_memmap.h" #include "tonc_memdef.h" // -------------------------------------------------------------------- // BITS and BITFIELDS // -------------------------------------------------------------------- /*! \defgroup grpCoreBit Bit(field) macros \ingroup grpCore */ /*! \{ */ //! \name Simple bit macros //\{ //! Create value with bit \a n set #define BIT(n) ( 1<<(n) ) //! Shift \a a by \a n #define BIT_SHIFT(a, n) ( (a)<<(n) ) //! Create a bitmask \a len bits long #define BIT_MASK(len) ( BIT(len)-1 ) //! Set the \a flag bits in \a word #define BIT_SET(y, flag) ( y |= (flag) ) //! Clear the \a flag bits in \a word #define BIT_CLEAR(y, flag) ( y &= ~(flag) ) //! Flip the \a flag bits in \a word #define BIT_FLIP(y, flag) ( y ^= (flag) ) //! Test whether all the \a flag bits in \a word are set #define BIT_EQ(y, flag) ( ((y)&(flag)) == (flag) ) //! Create a bitmask of length \a len starting at bit \a shift. #define BF_MASK(shift, len) ( BIT_MASK(len)<<(shift) ) //! Retrieve a bitfield mask of length \a starting at bit \a shift from \a y. #define _BF_GET(y, shift, len) ( ((y)>>(shift))&BIT_MASK(len) ) //! Prepare a bitmask for insertion or combining. #define _BF_PREP(x, shift, len) ( ((x)&BIT_MASK(len))<<(shift) ) //! Insert a new bitfield value \a x into \a y. #define _BF_SET(y, x, shift, len) \ ( y= ((y) &~ BF_MASK(shift, len)) | _BF_PREP(x, shift, len) ) //\} /*! \name some EVIL bit-field operations, >:) * These allow you to mimic bitfields with macros. Most of the * bitfields in the registers have foo_SHIFT and * foo_SHIFT macros indicating the mask and shift values * of the bitfield named foo in a variable. * These macros let you prepare, get and set the bitfields. */ //\{ //! Prepare a named bit-field for for insterion or combination. #define BFN_PREP(x, name) ( ((x)<>name##_SHIFT ) //! Set a named bitfield in \a y to \a x. Equivalent to y.name= x. #define BFN_SET(y, x, name) (y = ((y)&~name##_MASK) | BFN_PREP(x,name) ) //! Compare a named bitfield to named literal \a x. #define BFN_CMP(y, x, name) ( ((y)&name##_MASK) == (x) ) //! Massage \a x for use in bitfield \a name with pre-shifted \a x #define BFN_PREP2(x, name) ( (x) & name##_MASK ) //! Get the value of bitfield \a name from \a y, but don't down-shift #define BFN_GET2(y, name) ( (y) & name##_MASK ) //! Set bitfield \a name from \a y to \a x with pre-shifted \a x #define BFN_SET2(y,x,name) ( y = ((y)&~name##_MASK) | BFN_PREP2(x,name) ) //\} INLINE u32 bf_get(u32 y, uint shift, uint len); INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len); INLINE u32 bf_clamp(int x, uint len); INLINE int bit_tribool(u32 x, uint plus, uint minus); INLINE u32 ROR(u32 x, uint ror); /*! \} */ // -------------------------------------------------------------------- // DATA // -------------------------------------------------------------------- /*! \defgroup grpData Data routines \ingroup grpCore */ /*! \{ */ //! Get the number of elements in an array #define countof(_array) ( sizeof(_array)/sizeof(_array[0]) ) //! Align \a x to the next multiple of \a width. INLINE uint align(uint x, uint width); //! \name Copying and filling routines //\{ //! Simplified copier for GRIT-exported data. #define GRIT_CPY(dst, name) memcpy16(dst, name, name##Len/2) // Base memcpy/set replacements. void *tonccpy(void *dst, const void *src, uint size); void *__toncset(void *dst, u32 fill, uint size); INLINE void *toncset(void *dst, u8 src, uint count); INLINE void *toncset16(void *dst, u16 src, uint count); INLINE void *toncset32(void *dst, u32 src, uint count); // Fast memcpy/set extern "C" void memset16(void *dst, u16 hw, uint hwcount); extern "C" void memcpy16(void *dst, const void* src, uint hwcount); extern "C" IWRAM_CODE void memset32(void *dst, u32 wd, uint wcount); extern "C" IWRAM_CODE void memcpy32(void *dst, const void* src, uint wcount); //\} /*! \name Repeated-value creators These function take a hex-value and duplicate it to all fields, like 0x88 -> 0x88888888. */ //\{ INLINE u16 dup8(u8 x); INLINE u32 dup16(u16 x); INLINE u32 quad8(u8 x); INLINE u32 octup(u8 x); //\} //! \name Packing routines. //\{ INLINE u16 bytes2hword(u8 b0, u8 b1); INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3); INLINE u32 hword2word(u16 h0, u16 h1); //\} /*! \} */ // -------------------------------------------------------------------- // DMA // -------------------------------------------------------------------- /*! \addtogroup grpDma */ /*! \{ */ //! General purpose DMA transfer macro /*! \param _dst Destination address. \param _src Source address. \param count Number of transfers. \param ch DMA channel. \param mode DMA mode. */ #define DMA_TRANSFER(_dst, _src, count, ch, mode) \ do { \ REG_DMA[ch].cnt= 0; \ REG_DMA[ch].src= (const void*)(_src); \ REG_DMA[ch].dst= (void*)(_dst); \ REG_DMA[ch].cnt= (count) | (mode); \ } while(0) INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode); INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode); INLINE void dma3_cpy(void *dst, const void *src, uint size); INLINE void dma3_fill(void *dst, volatile u32 src, uint size); /*! \} */ // -------------------------------------------------------------------- // TIMER // -------------------------------------------------------------------- INLINE void profile_start(void); INLINE uint profile_stop(void); // -------------------------------------------------------------------- // TONE GENERATOR // -------------------------------------------------------------------- typedef enum { NOTE_C=0, NOTE_CIS, NOTE_D, NOTE_DIS, NOTE_E, NOTE_F, NOTE_FIS, NOTE_G, NOTE_GIS, NOTE_A, NOTE_BES, NOTE_B } eSndNoteId; extern const uint __snd_rates[12]; //! Gives the period of a note for the tone-gen registers. /*! GBA sound range: 8 octaves: [-2, 5]; 8*12= 96 notes (kinda). * \param note ID (range: [0,11>). See eSndNoteId. * \param oct octave (range [-2,4)>). */ #define SND_RATE(note, oct) ( 2048-(__snd_rates[note]>>(4+(oct))) ) // -------------------------------------------------------------------- // MISC // -------------------------------------------------------------------- /*! \defgroup grpCoreMisc Miscellaneous routines * \ingroup grpCore */ /*! \{ */ #define STR(x) #x //! Create text string from a literal #define XSTR(x) STR(x) //! \name Inline assembly //\{ //! Assembly comment #define ASM_CMT(str) asm volatile("@# " str) //! No$gba breakpoint #define ASM_BREAK() asm volatile("\tmov\t\tr11, r11") //! No-op; wait a bit. #define ASM_NOP() asm volatile("\tnop") //\} //! \name Sector checking //\{ u32 octant(int x, int y); u32 octant_rot(int x0, int y0); //\} //! \name Random numbers //\{ #define QRAN_SHIFT 15 #define QRAN_MASK ((1<>shift) & ( (1<>len; if(y) x= (~y)>>(32-len); return x; } //! Gives a tribool (-1, 0, or +1) depending on the state of some bits. /*! Looks at the \a plus and \a minus bits of \a flags, and subtracts their status to give a +1, -1 or 0 result. Useful for direction flags. \param flags Value with bit-flags. \param plus Bit number for positive result. \param minus Bit number for negative result. \return +1 if \a plus bit is set but \a minus bit isn't
-1 if \a minus bit is set and \a plus bit isn't
0 if neither or both are set. */ INLINE int bit_tribool(u32 flags, uint plus, uint minus) { return ((flags>>plus)&1) - ((flags>>minus)&1); } //! Rotate bits right. Yes, this does lead to a ror instruction. INLINE u32 ROR(u32 x, uint ror) { return (x<<(32-ror)) | (x>>ror); } // --- Data ----------------------------------------------------------- INLINE uint align(uint x, uint width) { return (x+width-1)/width*width; } //! VRAM-safe memset, byte version. Size in bytes. INLINE void *toncset(void *dst, u8 src, uint count) { return __toncset(dst, quad8(src), count); } //! VRAM-safe memset, halfword version. Size in hwords. INLINE void *toncset16(void *dst, u16 src, uint count) { return __toncset(dst, src|src<<16, count*2); } //! VRAM-safe memset, word version. Size in words. INLINE void *toncset32(void *dst, u32 src, uint count) { return __toncset(dst, src, count*4); } //! Duplicate a byte to form a halfword: 0x12 -> 0x1212. INLINE u16 dup8(u8 x) { return x|(x<<8); } //! Duplicate a halfword to form a word: 0x1234 -> 0x12341234. INLINE u32 dup16(u16 x) { return x|(x<<16); } //! Quadruple a byte to form a word: 0x12 -> 0x12121212. INLINE u32 quad8(u8 x) { return x*0x01010101; } //! Octuple a nybble to form a word: 0x1 -> 0x11111111 INLINE u32 octup(u8 x) { return x*0x11111111; } //! Pack 2 bytes into a word. Little-endian order. INLINE u16 bytes2hword(u8 b0, u8 b1) { return b0 | b1<<8; } //! Pack 4 bytes into a word. Little-endian order. INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3) { return b0 | b1<<8 | b2<<16 | b3<<24; } INLINE u32 hword2word(u16 h0, u16 h1) { return h0 | h1<<16; } // --- DMA ------------------------------------------------------------ /*! \addtogroup grpDma */ /*! \{ */ //! Generic DMA copy routine. /*! \param dst Destination address. * \param src Source address. * \param count Number of copies to perform. * \param ch DMA channel. * \param mode DMA transfer mode. * \note \a count is the number of copies, not the size in bytes. */ INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode) { REG_DMA[ch].cnt= 0; REG_DMA[ch].src= src; REG_DMA[ch].dst= dst; REG_DMA[ch].cnt= mode | count; } //! Generic DMA fill routine. /*! \param dst Destination address. * \param src Source value. * \param count Number of copies to perform. * \param ch DMA channel. * \param mode DMA transfer mode. * \note \a count is the number of copies, not the size in bytes. */ INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode) { REG_DMA[ch].cnt= 0; REG_DMA[ch].src= (const void*)&src; REG_DMA[ch].dst= dst; REG_DMA[ch].cnt= count | mode | DMA_SRC_FIXED; } //! Specific DMA copier, using channel 3, word transfers. /*! \param dst Destination address. * \param src Source address. * \param size Number of bytes to copy * \note \a size is the number of bytes */ INLINE void dma3_cpy(void *dst, const void *src, uint size) { dma_cpy(dst, src, size/4, 3, DMA_CPY32); } //! Specific DMA filler, using channel 3, word transfers. /*! \param dst Destination address. * \param src Source value. * \param size Number of bytes to copy * \note \a size is the number of bytes */ INLINE void dma3_fill(void *dst, volatile u32 src, uint size) { dma_fill(dst, src, size/4, 3, DMA_FILL32); } /*! \} */ // --- Random --------------------------------------------------------- //! Quick (and very dirty) pseudo-random number generator /*! \return random in range [0,8000h> */ INLINE int qran(void) { __qran_seed= 1664525*__qran_seed+1013904223; return (__qran_seed>>16) & QRAN_MAX; } //! Ranged random number /*! \return random in range [\a min, \a max> * \note (max-min) must be lower than 8000h */ INLINE int qran_range(int min, int max) { return (qran()*(max-min)>>QRAN_SHIFT)+min; } // --- Timer ---------------------------------------------------------- /*! \addtogroup grpTimer */ /*! \{ */ //! Start a profiling run /*! \note Routine uses timers 3 and 3; if you're already using these * somewhere, chaos is going to ensue. */ INLINE void profile_start(void) { REG_TM2D= 0; REG_TM3D= 0; REG_TM2CNT= 0; REG_TM3CNT= 0; REG_TM3CNT= TM_ENABLE | TM_CASCADE; REG_TM2CNT= TM_ENABLE; } //! Stop a profiling run and return the time since its start. /*! \return 32bit cycle count */ INLINE uint profile_stop(void) { REG_TM2CNT= 0; return (REG_TM3D<<16)|REG_TM2D; } /*! \} /addtogroup */ #endif // TONC_CORE