From f57fab6afe62f2a476ef4afa1842c81722816451 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 27 Jul 2022 05:55:18 +0300 Subject: [PATCH] initial commit --- .gitignore | 19 + Makefile | 102 + libs/maxmod/Makefile | 17 + libs/maxmod/license.txt | 23 + libs/maxmod/maxmod.h | 396 ++++ libs/maxmod/maxmod7.h | 483 ++++ libs/maxmod/mm_effect.S | 767 +++++++ libs/maxmod/mm_init_default.S | 97 + libs/maxmod/mm_main.S | 802 +++++++ libs/maxmod/mm_mas.S | 4960 ++++++++++++++++++++++++++++++++++++++++ libs/maxmod/mm_mas_arm.S | 612 +++++ libs/maxmod/mm_mixer_gba.S | 1367 +++++++++++ libs/maxmod/mm_types.h | 327 +++ libs/maxmod/mp_defs.inc | 117 + libs/maxmod/mp_format_mas.inc | 108 + libs/maxmod/mp_macros.inc | 195 ++ libs/maxmod/mp_mas.inc | 40 + libs/maxmod/mp_mas_structs.inc | 189 ++ libs/maxmod/mp_mixer_gba.inc | 42 + libs/maxmod/swi_gba.inc | 23 + src/asmutil.s | 38 + src/debug.c | 154 ++ src/debug.h | 39 + src/dma.c | 62 + src/dma.h | 12 + src/font8x8.c | 2565 +++++++++++++++++++++ src/game.h | 9 + src/gamescr.c | 69 + src/gbaregs.h | 365 +++ src/input.c | 39 + src/input.h | 24 + src/intr.c | 31 + src/intr.h | 39 + src/main.c | 59 + src/menuscr.c | 5 + src/polyfill.c | 303 +++ src/polyfill.h | 33 + src/sprite.c | 77 + src/sprite.h | 51 + src/timer.c | 55 + src/timer.h | 32 + src/util.c | 25 + src/util.h | 36 + src/xgl.c | 294 +++ src/xgl.h | 68 + tools/lutgen.c | 16 + 46 files changed, 15186 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 libs/maxmod/Makefile create mode 100644 libs/maxmod/license.txt create mode 100644 libs/maxmod/maxmod.h create mode 100644 libs/maxmod/maxmod7.h create mode 100644 libs/maxmod/mm_effect.S create mode 100644 libs/maxmod/mm_init_default.S create mode 100644 libs/maxmod/mm_main.S create mode 100644 libs/maxmod/mm_mas.S create mode 100644 libs/maxmod/mm_mas_arm.S create mode 100644 libs/maxmod/mm_mixer_gba.S create mode 100644 libs/maxmod/mm_types.h create mode 100644 libs/maxmod/mp_defs.inc create mode 100644 libs/maxmod/mp_format_mas.inc create mode 100644 libs/maxmod/mp_macros.inc create mode 100644 libs/maxmod/mp_mas.inc create mode 100644 libs/maxmod/mp_mas_structs.inc create mode 100644 libs/maxmod/mp_mixer_gba.inc create mode 100644 libs/maxmod/swi_gba.inc create mode 100644 src/asmutil.s create mode 100644 src/debug.c create mode 100644 src/debug.h create mode 100644 src/dma.c create mode 100644 src/dma.h create mode 100644 src/font8x8.c create mode 100644 src/game.h create mode 100644 src/gamescr.c create mode 100644 src/gbaregs.h create mode 100644 src/input.c create mode 100644 src/input.h create mode 100644 src/intr.c create mode 100644 src/intr.h create mode 100644 src/main.c create mode 100644 src/menuscr.c create mode 100644 src/polyfill.c create mode 100644 src/polyfill.h create mode 100644 src/sprite.c create mode 100644 src/sprite.h create mode 100644 src/timer.c create mode 100644 src/timer.h create mode 100644 src/util.c create mode 100644 src/util.h create mode 100644 src/xgl.c create mode 100644 src/xgl.h create mode 100644 tools/lutgen.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6244192 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +*.o +*.d +*.swp +cfg.mk +*.gba +*.elf +*.a +pngdump +mmutil +lutgen +*.ppm +*.png +*.sav +disasm +data +*.tar.gz +*.zip +pushdata +link.map diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..db4dd95 --- /dev/null +++ b/Makefile @@ -0,0 +1,102 @@ +src = $(wildcard src/*.c) +ssrc = $(wildcard src/*.s) data/lut.s +obj = $(src:.c=.o) $(ssrc:.s=.o) +dep = $(src:.c=.d) +name = gbajam22 +elf = $(name).elf +bin = $(name).gba + +libs = libs/maxmod/libmm.a + +TCPREFIX = arm-none-eabi- + +CPP = $(TCPREFIX)cpp +CC = $(TCPREFIX)gcc +AS = $(TCPREFIX)as +OBJCOPY = $(TCPREFIX)objcopy +OBJDUMP = $(TCPREFIX)objdump + +opt = -O3 -fomit-frame-pointer -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork +dbg = -g +inc = -I. -Ilibs/maxmod + +CFLAGS = $(opt) $(dbg) -pedantic -Wall -MMD $(def) $(inc) +ASFLAGS = -mthumb-interwork +LDFLAGS = -mthumb -mthumb-interwork $(libs) + +-include cfg.mk + +.PHONY: all +all: $(bin) $(bin_mb) + +$(bin): $(elf) + $(OBJCOPY) -O binary $(elf) $(bin) + gbafix -r0 $(bin) + +$(elf): $(obj) $(libs) + $(CC) -o $(elf) $(obj) -specs=gba.specs -Wl,-Map,link.map $(LDFLAGS) + +-include $(dep) + +src/data.o: src/data.s $(data) + +tools/pngdump/pngdump: + $(MAKE) -C tools/pngdump + +tools/lutgen: tools/lutgen.c + cc -o $@ $< -lm + +tools/mmutil/mmutil: + $(MAKE) -C tools/mmutil + +%.sraw: %.png tools/pngdump/pngdump + tools/pngdump/pngdump -o $@ -oc $(subst .sraw,.spal,$@) -os $(subst .sraw,.shade,$@) -s 8 $< + +%.raw: %.png tools/pngdump/pngdump + tools/pngdump/pngdump -o $@ -n $< + +%.pal: %.png tools/pngdump/pngdump + tools/pngdump/pngdump -o $@ -c $< + +data/lut.s: tools/lutgen + tools/lutgen >$@ + +data/snd.bin: $(audata) tools/mmutil/mmutil + tools/mmutil/mmutil -o$@ -hdata/snd.h $(audata) + +data/snd.h: data/snd.bin + +.PHONY: clean +clean: + rm -f $(obj) $(bin) $(bin_mb) $(elf) $(elf_mb) + +.PHONY: cleandep +cleandep: + rm -f $(dep) + +.PHONY: cleanlibs +cleanlibs: + $(MAKE) -C libs/maxmod clean + +.PHONY: install +install: $(bin) + if2a -n -f -W $< + +.PHONY: run +run: $(bin) + mgba -2 $(bin) + +.PHONY: debug +debug: $(elf) + mgba -2 -g $(bin) & + $(TCPREFIX)gdb $< + +.PHONY: disasm +disasm: $(elf) + $(OBJDUMP) -d $< >$@ + +.PHONY: libs +libs: $(libs) + +libs/maxmod/libmm.a: + $(MAKE) -C libs/maxmod diff --git a/libs/maxmod/Makefile b/libs/maxmod/Makefile new file mode 100644 index 0000000..f7a4356 --- /dev/null +++ b/libs/maxmod/Makefile @@ -0,0 +1,17 @@ +src = $(wildcard *.S) +obj = $(src:.S=.o) +lib_a = libmm.a + +TCPREFIX ?= arm-none-eabi- +CC = $(TCPREFIX)gcc +AS = $(TCPREFIX)as +AR = $(TCPREFIX)ar + +ASFLAGS = -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork -DSYS_GBA -DUSE_IWRAM + +$(lib_a): $(obj) + $(AR) rcs $@ $(obj) + +.PHONY: clean +clean: + rm -f $(obj) $(lib_a) diff --git a/libs/maxmod/license.txt b/libs/maxmod/license.txt new file mode 100644 index 0000000..265395b --- /dev/null +++ b/libs/maxmod/license.txt @@ -0,0 +1,23 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> + +#ifdef __cplusplus +extern "C" { +#endif + +// precalculated mix buffer lengths (in bytes) +#define MM_MIXLEN_8KHZ 544 // (8121 hz) +#define MM_MIXLEN_10KHZ 704 // (10512 hz) +#define MM_MIXLEN_13KHZ 896 // (13379 hz) +#define MM_MIXLEN_16KHZ 1056 // (15768 hz) +#define MM_MIXLEN_18KHZ 1216 // (18157 hz) +#define MM_MIXLEN_21KHZ 1408 // (21024 hz) +#define MM_MIXLEN_27KHZ 1792 // (26758 hz) +#define MM_MIXLEN_31KHZ 2112 // (31536 hz) + +// measurements of channel types (bytes) +#define MM_SIZEOF_MODCH 40 +#define MM_SIZEOF_ACTCH 28 +#define MM_SIZEOF_MIXCH 24 + +/**************************************************************************** + * mmInitDefault( mm_addr soundbank, mm_word number_of_channels ) + * + * Initialize Maxmod with default settings. + ****************************************************************************/ + +void mmInitDefault( mm_addr soundbank, mm_word number_of_channels ); + +/**************************************************************************** + * mmInit( mm_gba_system* setup ) + * + * Initialize system. Call once at startup. + ****************************************************************************/ + +void mmInit( mm_gba_system* setup ); + +/**************************************************************************** + * mmVBlank() + * + * Must be linked to the VBlank IRQ. + ****************************************************************************/ + +void mmVBlank( void ); + +/**************************************************************************** + * mmSetVBlankHandler( void* function ) + * + * Install user vblank handler + * + * function : Pointer to your VBlank handler. + ****************************************************************************/ + +void mmSetVBlankHandler( void* function ); + +/**************************************************************************** + * mmSetEventHandler( mm_callback handler ) + * + * Install handler to receive song events. + ****************************************************************************/ + +void mmSetEventHandler( mm_callback handler ); + +/**************************************************************************** + * mmFrame() + * + * Work routine. _Must_ be called every frame. + ****************************************************************************/ + +void mmFrame( void ) __attribute((long_call)); + + + +/**************************************************************************** + * + * Module Playback + * + ****************************************************************************/ + + + +/**************************************************************************** + * mmStart( mm_word id, mm_pmode mode ) + * + * Start module playback. + * + * id : ID of module to play. + * mode : Playback mode (loop/once) + ****************************************************************************/ + +void mmStart( mm_word id, mm_pmode mode ); + +/**************************************************************************** + * mmPause() + * + * Pause module playback, resume with mmResume(). + ****************************************************************************/ + +void mmPause( void ); + +/**************************************************************************** + * mmResume() + * + * Resume module playback, pause with mmPause(). + ****************************************************************************/ + +void mmResume( void ); + +/**************************************************************************** + * mmStop() + * + * Stop module playback. start again with mmStart(). + ****************************************************************************/ + +void mmStop( void ); + +/**************************************************************************** + * mmGetPosition() + * + * Get playback position. + ****************************************************************************/ + +mm_word mmGetPosition( void ); + +/**************************************************************************** + * mmPosition() + * + * Set playback position. + * + * position: New position in the module sequence. + ****************************************************************************/ + +void mmPosition( mm_word position ); + +/**************************************************************************** + * mmSetPosition() + * + * Set playback position (alias for mmPosition()). + * + * position: New position in the module sequence. + ****************************************************************************/ + +inline void mmSetPosition( mm_word position ) +{ + mmPosition( position ); +} + +/**************************************************************************** + * mmActive() + * + * Returns nonzero if module is playing. + ****************************************************************************/ + +int mmActive( void ); + +/**************************************************************************** + * mmJingle( mm_word module_ID ) + * + * Play module as jingle. Jingles are limited to 4 channels only. + * + * module_ID : ID of moudle (defined in soundbank header) + ****************************************************************************/ + +void mmJingle( mm_word module_ID ); + +/**************************************************************************** + * mmActiveSub() + * + * Returns nonzero if a jingle is actively playing. + ****************************************************************************/ + +int mmActiveSub( void ); + +/**************************************************************************** + * mmSetModuleVolume( mm_word volume ) + * mmSetJingleVolume( mm_word volume ) + * + * Set volume scaler for music/jingles. + * + * volume : 0->1024 = silent..normal + ****************************************************************************/ + +void mmSetModuleVolume( mm_word volume ); +void mmSetJingleVolume( mm_word volume ); + +/***************************************************************** + * mmSetModuleTempo( mm_word tempo ) + * + * Set tempo of playback. + * + * tempo : Fixed point (Q10) value representing tempo. + * Range = 0x200 -> 0x800 = 0.5 -> 2.0 + *****************************************************************/ + +void mmSetModuleTempo( mm_word tempo ); + +/***************************************************************** + * mmSetModulePitch( mm_word pitch ) + * + * Set pitch of playback. + * + * pitch : Range = 0x200 -> 0x800 = 0.5 -> 2.0 + *****************************************************************/ + +void mmSetModulePitch( mm_word pitch ); + +/**************************************************************************** + * mmPlayModule( mm_word address, mm_word mode, mm_word layer ) + * + * Play direct MAS file + ****************************************************************************/ + +void mmPlayModule( mm_word address, mm_word mode, mm_word layer ); + + + +/**************************************************************************** + * + * Sound Effects + * + ****************************************************************************/ + + + +/**************************************************************************** + * mmEffect( mm_word sample_ID ) + * + * Play a sound effect at its default frequency with full volume and + * centered panning. + * + * sample_ID : Sound effect ID. (defined in soundbank header) + ****************************************************************************/ + +mm_sfxhand mmEffect( mm_word sample_ID ); + +/**************************************************************************** + * mmEffectEx( mm_sound_effect* sound ) + * + * Play a sound effect with all parameters. + * + * sound : Sound effect attributes. + ****************************************************************************/ + +mm_sfxhand mmEffectEx( mm_sound_effect* sound ); + +/**************************************************************************** + * mmEffectVolume( mm_sfxhand handle, mm_word volume ) + * + * Set the volume of a sound effect. + * + * handle : Sound effect handle. + * volume : 0->65535 + ****************************************************************************/ + +void mmEffectVolume( mm_sfxhand handle, mm_word volume ); + +/**************************************************************************** + * mmEffectPanning( mm_sfxhand handle, mm_word panning ) + * + * Set the panning of a sound effect. + * + * handle : Sound effect handle. + * panning : 0->255 = left..right + ****************************************************************************/ + +void mmEffectPanning( mm_sfxhand handle, mm_byte panning ); + +/**************************************************************************** + * mmEffectRate( mm_sfxhand handle, mm_word rate ) + * + * Set the playback rate of an effect. + * + * handle : Sound effect handle. + * rate: 6.10 factor + ****************************************************************************/ + +void mmEffectRate( mm_sfxhand handle, mm_word rate ); + +/**************************************************************************** + * mmEffectScaleRate( mm_sfxhand handle, mm_word factor ) + * + * Scale the playback rate of an effect. + * + * handle : Sound effect handle. + * factor : 6.10 fixed point factor. + ****************************************************************************/ + +void mmEffectScaleRate( mm_sfxhand handle, mm_word factor ); + +/**************************************************************************** + * mmEffectActive( mm_sfxhand handle ) + * + * Indicates if a sound effect is active or not. + * + * handle : Sound effect handle. + ****************************************************************************/ + +mm_bool mmEffectActive( mm_sfxhand handle ); + +/**************************************************************************** + * mmEffectCancel( mm_sfxhand handle ) + * + * Stop sound effect. + * + * handle : Sound effect handle. + ****************************************************************************/ + +void mmEffectCancel( mm_sfxhand handle ); + +/**************************************************************************** + * mmEffectRelease( mm_sfxhand handle ) + * + * Release sound effect (invalidate handle and allow interruption) + * + * handle : Sound effect handle. + ****************************************************************************/ + +void mmEffectRelease( mm_sfxhand handle ); + +/**************************************************************************** + * mmSetEffectsVolume( mm_word volume ) + * + * Set master volume scale for effect playback. + * + * volume : 0->1024 representing 0%->100% volume + ****************************************************************************/ + +void mmSetEffectsVolume( mm_word volume ); + +/**************************************************************************** + * mmEffectCancelAll() + * + * Stop all sound effects + ****************************************************************************/ + +void mmEffectCancelAll(); + + + +#ifdef __cplusplus +} +#endif + +/**************************************************************************** + * Playback events + ****************************************************************************/ + +//--------------------------------------------------------------------------- +// This happens when Maxmod reads a SFx (or mod/xm EFx) effect from a module +// It will store 'x' in param_b +//--------------------------------------------------------------------------- +#define MMCB_SONGMESSAGE 0x2A +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// A module has finished playing +// param == 0 if main module, ==1 otherwise +//--------------------------------------------------------------------------- +#define MMCB_SONGFINISHED 0x2B +//--------------------------------------------------------------------------- + +/**************************************************************************** + * etc... + ****************************************************************************/ + +extern mm_byte mp_mix_seg; // current mixing segment +extern mm_word mp_writepos; // mixer's write position + +#endif diff --git a/libs/maxmod/maxmod7.h b/libs/maxmod/maxmod7.h new file mode 100644 index 0000000..a51b2d6 --- /dev/null +++ b/libs/maxmod/maxmod7.h @@ -0,0 +1,483 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> + +//---------------------------------------------------------------- +#ifdef __cplusplus +extern "C" { +#endif +//---------------------------------------------------------------- + +/***************************************************************** + * mmInstall( channel ) + * + * Install Maxmod. + * + * channel : IPC/FIFO channel to use, usually 7. + *****************************************************************/ + +void mmInstall( int fifo_channel ); + +/***************************************************************** + * mmLockChannels( mm_word bitmask ) + * + * Lock audio channels from being used by Maxmod. + * + * bitmask : Bitmask of which channels should be locked. + * (&1 = ch0, &2 = ch1, &4 = ch2, &8 = ch4, etc...) + *****************************************************************/ + +void mmLockChannels( mm_word bitmask ); + +/***************************************************************** + * mmUnlockChannels( mm_word bitmask ) + * + * Unlock audio channels so Maxmod can use them. + * + * bitmask : Bitmask of which channels should be unlocked. + * (&1 = ch0, &2 = ch1, &4 = ch2, &8 = ch4, etc...) + *****************************************************************/ + +void mmUnlockChannels( mm_word bitmask ); + +/***************************************************************** + * mmIsInitialize() + * + * Returns whether or not the system is ready for playback. + *****************************************************************/ + +mm_bool mmIsInitialized( void ); + +/***************************************************************** + * mmSelectMode( mm_mode_enum mode ) + * + * Select audio mode + * + * mode: + * MM_MODE_A : Hardware Mixing + * MM_MODE_B : Interpolated Mixing + * MM_MODE_C : Extended Mixing + *****************************************************************/ + +void mmSelectMode( mm_mode_enum mode ); + +/***************************************************************** + * mmFrame() + * + * Work routine (called automatically) + *****************************************************************/ + +void mmFrame( void ); + +// note about using sleep functions: +// do not use during an interrupt!! it's not safe +// and do not exit sleep unless it is already sleeping. + + + +/***************************************************************** + * + * Module Playback + * + *****************************************************************/ + + + +/***************************************************************** + * mmStart( mm_word module_ID, mm_pmode mode ) + * + * Start module playback + * + * module_ID : Index of module to play. (defined in soundbank header) + * mode : Mode of playback: MM_PLAY_ONCE or MM_PLAY_LOOP + *****************************************************************/ + +void mmStart( mm_word module_ID, mm_pmode mode ); + +/***************************************************************** + * mmPause() + * + * Pause module playback. + *****************************************************************/ + +void mmPause( void ); + +/***************************************************************** + * mmResume() + * + * Resume module playback + *****************************************************************/ + +void mmResume( void ); + +/***************************************************************** + * mmStop() + * + * Stop module playback. Start again (from the beginning) + * with mmStart(...). + *****************************************************************/ + +void mmStop( void ); + +/***************************************************************** + * mmPosition( mm_word position ) + * + * Set playback position. + * + * position : New position in module sequence. + *****************************************************************/ + +void mmPosition( mm_word position ); + +/***************************************************************** + * mmActive() + * + * Returns nonzero if module is playing + *****************************************************************/ + +mm_bool mmActive( void ); + +/***************************************************************** + * mmJingle( mm_word module_ID ) + * + * Play module as jingle. Jingles are limited to 4 channels only. + * + * module_ID : ID of module (defined in soundbank header) + *****************************************************************/ + +void mmJingle( mm_word module_ID ); + +/***************************************************************** + * mmActiveSub() + * + * Returns nonzero if a jingle is actively playing. + *****************************************************************/ + +mm_bool mmActiveSub( void ); + +/***************************************************************** + * mmSetModuleVolume( mm_word volume ) + * mmSetJingleVolume( mm_word volume ) + * + * Set volume scaler for music/jingles. + * + * volume : 0->1024 = silent..normal + *****************************************************************/ + +void mmSetModuleVolume( mm_word volume ); +void mmSetJingleVolume( mm_word volume ); + +/***************************************************************** + * mmPlayModule( mm_word address, mm_word mode, mm_word layer ) + * + * Play direct MAS file + *****************************************************************/ + +void mmPlayModule( mm_word address, mm_word mode, mm_word layer ); + + + +/***************************************************************** + * + * Sound Effects + * + *****************************************************************/ + + + +/***************************************************************** + * mmEffect( mm_word sample_ID ) + * + * Play a sound effect at its default frequency with full volume + * and centered panning. Effect must be loaded first via + * mmLoadEffect. + * + * sample_ID : Sound effect ID. (defined in soundbank header) + *****************************************************************/ + +mm_sfxhand mmEffect( mm_word sample_ID ); + +/***************************************************************** + * mmEffectEx( mm_sound_effect* sound ) + * + * Play a sound effect with the parameters supplied. + * + * sound : Sound effect attributes. + *****************************************************************/ + +mm_sfxhand mmEffectEx( mm_sound_effect* sound ); + +/***************************************************************** + * mmEffectVolume( mm_sfxhand handle, mm_word volume ) + * + * Set the volume of a sound effect. + * + * handle : Sound effect handle. + * volume : 0->65535 + *****************************************************************/ + +void mmEffectVolume( mm_sfxhand handle, mm_word volume ); + +/***************************************************************** + * mmEffectPanning( mm_sfxhand handle, mm_word panning ) + * + * Set the panning of a sound effect. + * + * handle : Sound effect handle. + * panning : 0->255 = left..right + *****************************************************************/ + +void mmEffectPanning( mm_sfxhand handle, mm_byte panning ); + +/***************************************************************** + * mmEffectRate( mm_sfxhand handle, mm_word rate ) + * + * Set the playback rate of an effect. + * + * handle : Sound effect handle. + * rate: 6.10 factor + *****************************************************************/ + +void mmEffectRate( mm_sfxhand handle, mm_word rate ); + +/***************************************************************** + * mmEffectScaleRate( mm_sfxhand handle, mm_word factor ) + * + * Scale the playback rate of an effect. + * + * handle : Sound effect handle. + * factor : 6.10 fixed point factor. + *****************************************************************/ + +void mmEffectScaleRate( mm_sfxhand handle, mm_word factor ); + +/***************************************************************** + * mmEffectCancel( mm_sfxhand handle ) + * + * Stop sound effect. + * + * handle : Sound effect handle. + *****************************************************************/ + +void mmEffectCancel( mm_sfxhand handle ); + +/***************************************************************** + * mmEffectRelease( mm_sfxhand handle ) + * + * Release sound effect (invalidate handle and allow interruption) + * + * handle : Sound effect handle. + *****************************************************************/ + +void mmEffectRelease( mm_sfxhand handle ); + +/***************************************************************** + * mmSetEffectsVolume( mm_word volume ) + * + * Set master volume scale for effect playback. + * + * volume : 0->1024 representing 0%->100% volume + *****************************************************************/ + +void mmSetEffectsVolume( mm_word volume ); + +/***************************************************************** + * mmEffectCancelAll() + * + * Stop all sound effects + *****************************************************************/ + +void mmEffectCancelAll(); + + + +/***************************************************************** + * + * Streaming + * + *****************************************************************/ + + +/***************************************************************** + * mmStreamOpen( mm_stream* stream, mm_addr wavebuffer, mm_addr workbuffer ) + * + * Open audio stream. + * + * stream : Configuration struct + * wavebuffer : wave memory, must be aligned + * workbuffer : work memory, must be aligned + *****************************************************************/ + +void mmStreamOpen( mm_stream* stream, mm_addr wavebuffer, mm_addr workbuffer ); + +/***************************************************************** + * mmStreamUpdate() + * + * Fills the stream with wave data. + * This only needs to be called in 'manual' mode. It + * is called automatically in 'auto' mode. + *****************************************************************/ + +void mmStreamUpdate( void ); + +/***************************************************************** + * mmStreamClose() + * + * Close audio stream. + *****************************************************************/ + +void mmStreamClose( void ); + +/***************************************************************** + * mmStreamGetPosition() + * + * Get number of samples elapsed since the stream was opened. + * The 32-bit value will wrap every 36 hours or so (at 32khz) + *****************************************************************/ + +mm_word mmStreamGetPosition(); + + + +/***************************************************************** + * + * Reverb + * + *****************************************************************/ + + + +/***************************************************************** + * mmReverbEnable() + * + * Enable reverb system. (use before configuring!) + *****************************************************************/ + +void mmReverbEnable( void ); + +/***************************************************************** + * mmReverbConfigure( mm_reverb_cfg* config ) + * + * Configure reverb parameters. + * config : Configuration data. + *****************************************************************/ + +void mmReverbConfigure( mm_reverb_cfg* config ); + +/***************************************************************** + * mmReverbStart( mm_reverbch channels ) + * + * Start reverb output. + *****************************************************************/ + +void mmReverbStart( mm_reverbch channels ); + +/***************************************************************** + * mmReverbStop( mm_reverch channels ) + * + * Stop reverb output. + *****************************************************************/ + +void mmReverbStop( mm_reverbch channels ); + +/***************************************************************** + * mmReverbBufferSize( mm_word bit_depth, mm_word sampling_rate, + * mm_word delay ) + * + * Calculate reverb buffer size based on bit depth, delay + * and sampling rate. + * + * bit_depth : Pass 8 or 16 for 8-bit/16-bit + * sampling_rate : + * delay : In milliseconds + * + * Returns size in WORDS. + *****************************************************************/ + +static inline mm_word mmReverbBufferSize( mm_word bit_depth, mm_word sampling_rate, mm_word delay ) +{ + if( bit_depth == 16 ) + { + return ((((sampling_rate * delay * 2) / 1000) + 3) & (~3)) / 4; + } + else + { + return ((((sampling_rate * delay) / 1000) + 3) & (~3)) / 4; + } +} + +/***************************************************************** + * mmReverbDisable() + * + * Disable reverb system. + *****************************************************************/ + +void mmReverbDisable( void ); + + + +//---------------------------------------------------------------- +#ifdef __cplusplus +} +#endif +//---------------------------------------------------------------- + +/***************************************************************** + * Playback events + *****************************************************************/ + +//---------------------------------------------------------------- +// This happens when Maxmod reads an SFx (or mod/xm EFx) effect +// from a module. It will pass 'x' in param. +//---------------------------------------------------------------- +#define MMCB_SONGMESSAGE 0x2A +//---------------------------------------------------------------- + +//---------------------------------------------------------------- +// A module has finished playing. +// param == 0 if main module, ==1 otherwise +//---------------------------------------------------------------- +#define MMCB_SONGFINISHED 0x2B +//---------------------------------------------------------------- + +//======================================================================================= +// misc definitions / references +//======================================================================================= + +// main/sub layer attributes +extern mm_modlayer mmLayerMain; +extern mm_modlayer mmLayerSub; + +#endif diff --git a/libs/maxmod/mm_effect.S b/libs/maxmod/mm_effect.S new file mode 100644 index 0000000..5c92ffc --- /dev/null +++ b/libs/maxmod/mm_effect.S @@ -0,0 +1,767 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> 0x10000 = external sample + bne 1f // + ldr r0,=mmSampleBank // ID# otherwise + ldr r0, [r0] // + lsl r1, #2 // + ldr r1, [r0, r1] // + lsl r1, #8 // + lsr r1, #8 // + beq .invalid_sample + add r1, #8 // + ldr r0,=0x2000000 // + add r1, r0 // +1: // + str r1, [r3, #MIXER_CHN_SAMP] // + + + ldrh r0, [r4, #MM_SFX_RATE] // set pitch to original * pitch + ldrh r1, [r1, #C_SAMPLEC_DFREQ] // + mul r1, r0 // + lsr r1, #10 // + strh r1, [r3, #MIXER_CHN_FREQ] // + + mov r1, #0 // clear sample offset + str r1, [r3, #MIXER_CHN_READ] // + + ldrb r1, [r4, #MM_SFX_PANNING] // set panning + startbit + lsr r1, #1 // + add r1, #0x80 // + strb r1, [r3, #MIXER_CHN_CNT] // + + ldrb r1, [r4, #MM_SFX_VOLUME] // set volume + ldr r0,=mm_sfx_mastervolume + ldr r0, [r0] + mul r1, r0 +// lsr r0, #10 + lsr r2, r1, #2 +// lsl r2, r1, #8 + + strh r2, [r3, #MIXER_CHN_VOL] // + + b .valid_sample +.invalid_sample: + mov r0, #0 + str r0, [r3, #MIXER_CHN_SAMP] + +.valid_sample: + +#endif + + mov r0, r5 // return handle + pop {r4-r6} // + ret1 // + +.no_available_channels: + mov r0, #0 // return bad + pop {r4-r6} // + ret1 // + + + +/*********************************************************************** + * mme_get_channel_index + * + * Test handle and return mixing channel index + ***********************************************************************/ + .thumb_func +mme_get_channel_index: + + lsl r1, r0, #24 // mask and test channel# + lsr r1, #24-1 // + cmp r1, #0 // + beq .invalid_handle // + cmp r1, #channelCount*2 // + bgt .invalid_handle // + + ldr r2,=mm_sfx_channels-2 // check if instances match + ldrh r3, [r2, r1] // + lsr r1, r3, #8 // + lsr r2, r0, #8 // + cmp r1, r2 // + bne .invalid_handle // + + lsl r3, #24 // mask channel# + lsr r3, #24 // + sub r3, #1 // + bx lr // + +.invalid_handle: // return invalid handle + mov r3, #0 // + mvn r3, r3 // + bx lr // + +/*********************************************************************** + * mmEffectActive( handle ) + * + * Indicates if a sound effect is active or not + ***********************************************************************/ + .global mmEffectActive + .thumb_func +mmEffectActive: + push {lr} // + bl mme_get_channel_index // + cmp r3, #0 // if r3 >= 0, it is active + bge .active // + mov r0, #0 // return false + pop {r3} // + bx r3 // + +.active: // + mov r0, #1 // return true + pop {r3} // + bx r3 // + +/*********************************************************************** + * mme_clear_channel(ch) + * + * Clear channel entry and bitmask + * r3 preserved + ***********************************************************************/ + .thumb_func +mme_clear_channel: + mov r1, #0 + ldr r2,=mm_sfx_channels // clear effect channel + lsl r0, #1 // + strh r1, [r2, r0] // + + mov r1, #1 // clear effect bitmask + lsr r0, #1 // + lsl r1, r0 // + ldr r2,=mm_sfx_bitmask // + ldr r0, [r2, #4] + orr r0, r1 + str r0, [r2, #4] + ldr r0, [r2] // + bic r0, r1 // + str r0, [r2] // + bx lr + +/*********************************************************************** + * mmEffectVolume( handle, volume ) + * + * Set effect volume + * + * volume 0..255 + ***********************************************************************/ + .global mmEffectVolume + .thumb_func +mmEffectVolume: + + push {r1, lr} + + bl mme_get_channel_index + pop {r1} + bmi 1f + + ldr r0,=mm_sfx_mastervolume + ldr r0, [r0] + mul r1, r0 + + #ifdef SYS_NDS + + lsr r1, #2 + + #endif + + #ifdef SYS_GBA + + lsr r1, #10 + + #endif + + mov r0, r3 + + bl mmMixerSetVolume + +1: ret0 + +/*********************************************************************** + * mmEffectPanning( handle, panning ) + * + * Set effect panning + * + * panning 0..255 + ***********************************************************************/ + .global mmEffectPanning + .thumb_func +mmEffectPanning: + + push {r1, lr} + bl mme_get_channel_index + pop {r1} + bmi 1f + + mov r0, r3 + bl mmMixerSetPan + +1: ret0 + +/*********************************************************************** + * mmEffectRate( handle, rate ) + * + * Set effect playback rate + ***********************************************************************/ + .global mmEffectRate + .thumb_func +mmEffectRate: + + push {r1, lr} + bl mme_get_channel_index + pop {r1} + bmi 1f + + mov r0, r3 + bl mmMixerSetFreq + +1: ret0 + +/*********************************************************************** + * mmEffectCancel( handle ) + * + * Stop sound effect + ***********************************************************************/ + .global mmEffectCancel + .thumb_func +mmEffectCancel: + + push {r0, lr} + + bl mme_get_channel_index + + pop {r0} + + bmi 1f + + mov r1, #MCA_SIZE // free achannel + mul r1, r3 // + ldr r2,=mm_achannels // + ldr r2, [r2] // + add r2, r1 // + mov r1, #ACHN_BACKGROUND // + strb r1, [r2, #MCA_TYPE] // + mov r1, #0 // + strb r1, [r2, #MCA_FVOL] // clear volume for channel allocator + + lsl r0, #24 + lsr r0, #24 + sub r0, #1 + bl mme_clear_channel + + mov r1, #0 // zero voice volume + mov r0, r3 // + bl mmMixerSetVolume // + + mov r0, #1 + ret1 +1: + mov r0, #0 + ret1 + +/*********************************************************************** + * mmEffectRelease( channel ) + * + * Release sound effect (allow interruption) + ***********************************************************************/ + .global mmEffectRelease + .thumb_func +mmEffectRelease: + + push {r0, lr} + + bl mme_get_channel_index + pop {r0} + + bmi 1f + + mov r1, #MCA_SIZE // release achannel + mul r1, r3 // + ldr r2,=mm_achannels // + ldr r2, [r2] // + add r2, r1 // + mov r1, #ACHN_BACKGROUND // + strb r1, [r2, #MCA_TYPE] // + + lsl r0, #24 + lsr r0, #24 + sub r0, #1 + bl mme_clear_channel + +1: ret0 + +/*********************************************************************** + * mmEffectScaleRate( channel, factor ) + * + * Scale sampling rate by 6.10 factor + ***********************************************************************/ + .global mmEffectScaleRate + .thumb_func +mmEffectScaleRate: + + push {r1,lr} + + bl mme_get_channel_index + pop {r1} + + bmi 1f + + mov r0, r3 + bl mmMixerMulFreq + +1: ret0 + +/*********************************************************************** + * mmSetEffectsVolume( volume ) + * + * set master volume scale, 0->1024 + ***********************************************************************/ + .global mmSetEffectsVolume + .thumb_func +mmSetEffectsVolume: + + lsr r1, r0, #10 + beq 1f + mov r0, #1 + lsl r0, #10 + +1: ldr r1,=mm_sfx_mastervolume + str r0, [r1] + bx lr + +/*********************************************************************** + * mmEffectCancelAll() + * + * Stop all sound effects + ***********************************************************************/ + .global mmEffectCancelAll + .thumb_func +mmEffectCancelAll: + + push {r4-r7,lr} + + ldr r4,=mm_sfx_bitmask + ldr r4, [r4] + ldr r6,=mm_sfx_channels + mov r5, #0 + + + lsr r4, #1 + bcc .mmeca_next +.mmeca_process: + + ldrb r7, [r6, r5] + sub r7, #1 + bmi .mmeca_next + + mov r0, r7 + mov r1, #0 + bl mmMixerSetVolume + + ldr r0,=mm_achannels // free achannel + ldr r0, [r0] // + mov r1, #MCA_SIZE // + mul r1, r7 // + add r0, r1 // + mov r1, #ACHN_BACKGROUND // + strb r1, [r0, #MCA_TYPE] // + mov r1, #0 + strb r1, [r0, #MCA_FVOL] // + +.mmeca_next: + add r5, #2 + lsr r4, #1 + bcs .mmeca_process + bne .mmeca_next + + bl mmResetEffects + + POP {r4-r7} + pop {r3} + bx r3 + +/*********************************************************************** + * mmUpdateEffects() + * + * Update sound effects + ***********************************************************************/ + .global mmUpdateEffects + .thumb_func +mmUpdateEffects: + + push {r4-r6,lr} + + ldr r4,=mm_sfx_bitmask + ldr r4, [r4] + ldr r6,=mm_sfx_channels + mov r5, #0 + + lsr r4, #1 + bcc .next_channel +.process_channel: + + ldrb r0, [r6, r5] // get channel index + sub r0, #1 // + bmi .next_channel // + + GET_MIXCH r1 + + mov r2, #MIXER_CHN_SIZE // get mixing channel pointer + mul r2, r0 // + add r1, r2 // + + #ifdef SYS_NDS // test if channel is still active + // + ldr r2, [r1, #MIXER_CHN_SAMP] // + lsl r2, #8 // + bne .next_channel // + // + #else // + // + ldr r2, [r1, #MIXER_CHN_SRC] // + asr r2, #31 // + beq .next_channel // + // + #endif // + + ldr r1,=mm_achannels // free achannel + ldr r1, [r1] // + mov r2, #MCA_SIZE // + mul r2, r0 // + add r1, r2 // + mov r0, #0 // + strb r0, [r1, #MCA_TYPE] // + strb r0, [r1, #MCA_FLAGS] // + strb r0, [r6, r5] + +.next_channel: + add r5, #2 // look for another set bit + lsr r4, #1 // + bcs .process_channel // + add r5, #2 // + lsr r4, #1 // + bcs .process_channel // + bne .next_channel // + + mov r4, #0 + mov r5, #1 + lsl r5, #32-channelCount + ldr r6,=mm_sfx_channels + +.build_new_bitmask: + ldrb r0, [r6] + add r6, #2 + cmp r0, #0 + beq 1f + orr r4, r5 +1: lsl r5, #1 + bne .build_new_bitmask + + lsr r4, #32-channelCount + ldr r0,=mm_sfx_bitmask + ldr r1, [r0] // r1 = bits that change from 1->0 + mov r2, r1 + eor r1, r4 + and r1, r2 + + str r4, [r0] + ldr r4, [r0, #4] + orr r4, r1 + str r4, [r0, #4] // write 1->0 mask + + pop {r4-r6,pc} + +.pool + +.end diff --git a/libs/maxmod/mm_init_default.S b/libs/maxmod/mm_init_default.S new file mode 100644 index 0000000..d5b3cd0 --- /dev/null +++ b/libs/maxmod/mm_init_default.S @@ -0,0 +1,97 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> mixlen? + blt .mpf_mix_adv @ no, mix and process tick + b .mpf_mix @ yes, mix the rest of samples + +.mpf_mix_adv: + + mov r1, #MPL_SAMPCOUNT @ reset sample counter + mov r7, #0 @ + strh r7, [r0,r1] @ + sub r4, r5 @ subtract from #samples to mix + + PROF_START + + mov r0, r5 + ldr r7,=mmMixerMix @ mix samples + bl _call_via_r7 + + PROF_END 0 + + ldr r7,=mppProcessTick + bl _call_via_r7 + + b .mpf_mix_advr @ process more samples +.mpf_mix: + +@ add samples remaining to SAMPCOUNT +@ and mix more samples + + mov r1, #MPL_SAMPCOUNT + add r6, r4 + strh r6, [r0, r1] + mov r0, r4 + PROF_START + ldr r1,=mmMixerMix + bl _call_via_r1 + PROF_END 0 + + pop {r4-r7} + ret1 @ return to user + +.mpf_no_mainlayer: + +@ main layer isn't active, +@ mix full amount + + mov r0, r4 + + PROF_START + ldr r1,=mmMixerMix + bl _call_via_r1 + PROF_END 0 + + pop {r4-r7} + ret1 + +.pool + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + + + +/****************************************************************************** + * + * NDS + * + ******************************************************************************/ + + + +//----------------------------------------------------------------------------- +#ifdef SYS_NDS +//----------------------------------------------------------------------------- + + .TEXT + .THUMB + .ALIGN 2 + +/****************************************************************************** + * mmSuspendIRQ_t + * + * Function to disable interrupts via the status register + ******************************************************************************/ + .global mmSuspendIRQ_t + .thumb_func +mmSuspendIRQ_t: + ldr r0,=1f + bx r0 + +.arm +.align 2 +1: mrs r0, cpsr + and r1, r0, #0x80 + orr r0, #0x80 + msr cpsr, r0 + str r1, previous_irq_state + bx lr +.thumb + +/****************************************************************************** + * mmRestoreIRQ_t + * + * Function to enable interrupts via the status register + ******************************************************************************/ + .global mmRestoreIRQ_t + .thumb_func +mmRestoreIRQ_t: + ldr r0,=1f + bx r0 + +.arm +.align 2 +1: mrs r0, cpsr + ldr r1, previous_irq_state + bic r0, #0x80 + orr r0, r1 + msr cpsr, r0 + bx lr + +.thumb + +previous_irq_state: + .space 4 + + .thumb_func +/****************************************************************************** + * mmIsInitialized() + * + * Returns true if the system is ready for playback + ******************************************************************************/ + .global mmIsInitialized + .thumb_func +mmIsInitialized: + ldr r0,=mmInitialized + ldrb r0, [r0] + bx lr + +/****************************************************************************** + * mmInit7() + * + * Initialize system + ******************************************************************************/ + .global mmInit7 + .thumb_func +mmInit7: + push {lr} + mov r0, #0x08 + ldr r1,=mmFrame + bl irqSet + + mov r0, #0x08 + bl irqEnable + + ldr r0,=0x400 // set volumes + bl mmSetModuleVolume // + ldr r0,=0x400 // + bl mmSetJingleVolume // + ldr r0,=0x400 // + bl mmSetEffectsVolume // + + ldr r0,=mmInitialized // set initialized flag + mov r1, #42 // + strb r1, [r0] // + + ldr r0,=0xFFFF // select all hardware channels + bl mmUnlockChannels // + + ldr r0,=mm_achannels // setup channel addresses + ldr r1,=mm_rds_achannels // + str r1, [r0] // + ldr r1,=mm_rds_pchannels // + str r1, [r0,#4] // + mov r1, #32 // 32 channels + str r1, [r0,#8] // + str r1, [r0,#12] // + + ldr r0,=0x400 + bl mmSetModuleTempo + + ldr r0,=0x400 + bl mmSetModulePitch + + bl mmResetEffects + + bl mmMixerInit // setup mixer + + ldr r0,=mmEventForwarder // forward events + bl mmSetEventHandler + + ldr r0,=mmInitialized // set initialized flag + mov r1, #42 // + strb r1, [r0] // + +.exit_r3: + pop {r3} + bx r3 + +/****************************************************************************** + * mmInstall( channel ) + * + * Install ARM7 system + ******************************************************************************/ + .global mmInstall + .thumb_func +mmInstall: + push {lr} + + ldr r1,=mmInitialized // not initialized until we get soundbank data + mov r2, #0 // + strb r2, [r1] // + + bl mmSetupComms // setup communication + + b .exit_r3 + +/****************************************************************************** + * mmEventForwarder( msg, param ) + * + * Forward event to arm9 + ******************************************************************************/ + .thumb_func +mmEventForwarder: + + push {lr} + lsl r1, #8 + orr r0, r1 + mov r1, #1 + lsl r1, #20 + orr r0, r1 + bl mmARM9msg + pop {pc} + +/****************************************************************************** + * mmGetSoundBank( n_songs, bank ) + * + * Load sound bank address + ******************************************************************************/ + .global mmGetSoundBank + .thumb_func +mmGetSoundBank: + ldr r2,=mmModuleCount // save data + stmia r2!, {r0,r1} // + + lsl r0, #2 // also sample bank address + add r1, r0 // + stmia r2!, {r1} // + +//------------------------------------------------ +// initialize system +//------------------------------------------------ + + b mmInit7 + +/****************************************************************************** + * mmFrame() + * + * Routine function + ******************************************************************************/ + .global mmFrame + .thumb_func +mmFrame: + + push {lr} + + ldr r0,=mmInitialized // catch not-initialized + ldrb r0, [r0] // + cmp r0, #42 // + bne 1f // + + bl mmMixerPre // <-- critical timing + + ldr r0,=0x4000208 // enable irq + mov r1, #1 // + strh r1, [r0] // + + bl mmUpdateEffects // update sound effects + bl mmPulse // update module playback + bl mmMixerMix // update audio + + + bl mmSendUpdateToARM9 + +1: bl mmProcessComms // process communications + + ret1 + +.pool + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +.end +//----------------------------------------------------------------------------- + diff --git a/libs/maxmod/mm_mas.S b/libs/maxmod/mm_mas.S new file mode 100644 index 0000000..9cc9c9e --- /dev/null +++ b/libs/maxmod/mm_mas.S @@ -0,0 +1,4960 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> 1024 + ******************************************************************************/ + .global mmSetModuleVolume + .thumb_func +mmSetModuleVolume: + +@ clamp volume 0->1024 + lsr r1, r0, #10 + beq 1f + mov r0, #1 + lsl r0, #10 + +@ set volume +1: ldr r1,=mmLayerMain + mov r2, #MPL_VOLUME + strh r0, [r1, r2] + bx lr + +/****************************************************************************** + * mmSetJingleVolume( volume ) + * + * Set master jingle volume. + * + * volume : 0->1024 + ******************************************************************************/ + .global mmSetJingleVolume + .thumb_func +mmSetJingleVolume: + +@ clamp volume 0->1024 + lsr r1, r0, #10 + beq 1f + mov r0, #1 + lsl r0, #10 + +@ set volume +1: ldr r1,=mmLayerSub @mpp_layerB + mov r2, #MPL_VOLUME + strh r0, [r1, r2] + bx lr + +/****************************************************************************** + * mppStop() [[internal function]] + * + * Stop module playback. + ******************************************************************************/ + .thumb_func +mppStop: + + push {lr} + + ldr r0,=mpp_clayer + ldrb r0, [r0] + + cmp r0, #0 + beq 1f + ldr r5,=mmLayerSub + ldr r6,=mm_schannels + mov r7, #MP_SCHANNELS + b 2f +1: ldr r5,=mmLayerMain + @ldr r6,=mpp_pchannels + ldr r6,=mm_pchannels + ldr r6,[r6] + @mov r7, #MP_MCHANNELS + ldr r7,=mm_num_mch + ldr r7,[r7] +2: + + mov r0, #0 + strb r0, [r5, #MPL_ISPLAYING] + + mov r1, #MPL_VALID + strb r0, [r5, r1] + + bl mpp_resetchannels + pop {r0} + bx r0 + +/****************************************************************************** + * mmGetPosition() + * + * Get playback position + ******************************************************************************/ + .global mmGetPosition + .thumb_func +mmGetPosition: + + ldr r1,=mmLayerMain + ldrb r0, [r1, #MPL_POSITION] + bx lr + +/****************************************************************************** + * mmPosition( position ) + * + * Set playback position + ******************************************************************************/ + .global mmPosition + .thumb_func +mmPosition: + + push {r4-r7,lr} + ldr r5,=mmLayerMain + ldr r6,=mm_pchannels + ldr r6,[r6] + ldr r7,=mm_num_mch + ldr r7, [r7] + + push {r0} +// bl mpp_resetchannels + + pop {r0} + bl mpp_setposition + + pop {r4-r7} + pop {r3} + bx r3 + +/****************************************************************************** + * mmSetModuleTempo( tempo ) + * + * Set master tempo + * + * tempo : x.10 fixed point tempo, 0.5->2.0 + ******************************************************************************/ + .global mmSetModuleTempo + .thumb_func +mmSetModuleTempo: + + push {r5,lr} + + mov r1, #1 // clamp value: 512->2048 + lsl r1, #11 // + cmp r0, r1 // + ble 1f // + mov r0, r1 // +1: mov r1, #1 // + lsl r1, #9 // + cmp r0, r1 // + bge 1f // + mov r0, r1 // +1: + + ldr r1,=mm_mastertempo + str r0, [r1] + + ldr r5,=mmLayerMain + ldr r0,=mpp_clayer + mov r1, #0 + strb r1, [r0] + + ldrb r0, [r5, #MPL_BPM] + cmp r0, #0 + beq 1f + bl mpp_setbpm + +1: pop {r5} + pop {r3} + bx r3 + +/****************************************************************************** + * mmSetModulePitch( pitch ) + * + * Set master pitch + * + * pitch : x.10 fixed point value, range = 0.5->2.0 + ******************************************************************************/ + .global mmSetModulePitch + .thumb_func +mmSetModulePitch: + push {r5,lr} + + mov r1, #1 // clamp value: 512->2048 + lsl r1, #11 // + cmp r0, r1 // + ble 1f // + mov r0, r1 // +1: mov r1, #1 // + lsl r1, #9 // + cmp r0, r1 // + bge 1f // + mov r0, r1 // +1: + + ldr r1,=mm_masterpitch + str r0, [r1] + +1: pop {r5} + pop {r3} + bx r3 + +.pool + +//----------------------------------------------------------------------------- +#ifdef SYS_NDS7 +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mmSetResolution( divider ) + * + * Set update resolution + ******************************************************************************/ + .global mmSetResolution + .thumb_func +mmSetResolution: + + push {r5, lr} + + ldr r1,=mpp_resolution + str r0, [r1] + + ldr r5,=mmLayerMain + + ldr r0,=mpp_clayer + mov r1, #0 + strb r1, [r0] + + ldrb r0, [r5, #MPL_BPM] + cmp r0, #0 + beq 1f + bl mpp_setbpm +1: ldr r5,=mmLayerSub + + ldr r0,=mpp_clayer + mov r1, #1 + strb r1, [r0] + + ldrb r0, [r5, #MPL_BPM] + cmp r0, #0 + beq 1f + bl mpp_setbpm +1: pop {r5} + pop {r3} + bx r3 + +#endif + +/****************************************************************************** + * mmStop() + * + * Stop module playback. + ******************************************************************************/ + .global mmStop + .thumb_func +mmStop: + + push {r4-r7,lr} + ldr r1,=mpp_clayer + mov r0, #0 + strb r0, [r1] + bl mppStop + pop {r4-r7} + ret3 + +/****************************************************************************** + * mpp_resetvars() + * + * Reset pattern variables + * Input r5 = layer + ******************************************************************************/ + .thumb_func +mpp_resetvars: + + mov r0, #255 + strb r0, [r5, #MPL_PATTJUMP] + mov r0, #0 + strb r0, [r5, #MPL_PATTJUMP_ROW] + bx lr + +/****************************************************************************** + * mpp_setbpm( bpm ) + * + * Set BPM. bpm = 32..255 + * Input r5 = layer + ******************************************************************************/ + .thumb_func +mpp_setbpm: + + strb r0, [r5, #MPL_BPM] + +#ifdef SYS_GBA + + ldr r1,=mpp_clayer + ldrb r1, [r1] + cmp r1, #0 + bne 1f + + ldr r1,=mm_mastertempo // multiply by master tempo + ldr r1, [r1] // + mul r1, r0 // + lsr r1, #10 // + + ldr r0,=mm_bpmdv @ samples per tick ~= mixfreq / (bpm/2.5) ~= mixfreq*2.5/bpm + ldr r0,[r0] + + swi SWI_DIVIDE @ SWI 07h, divide r1/r0 + lsr r0, #1 @ multiple of two + lsl r0, #1 @ --------------- + mov r1, #MPL_TICKRATE + strh r0, [r5, r1] @ + mov r1, #MPL_SAMPCOUNT +// mov r0, #0 +// strh r0, [r5, r1] + bx lr @ return + +1: @ SUB LAYER, time using vsync (rate = bpm/2.5 / 59.7) + + lsl r0, #15 + mov r1, #149 + swi SWI_DIVIDE + mov r1, #MPL_TICKRATE + strh r0, [r5, r1] + bx lr + +#endif + +#ifdef SYS_NDS + +@ vsync = ~59.8261 HZ (says GBATEK) +@ divider = hz * 2.5 * 64 + + ldr r1,=mpp_clayer + ldrb r1, [r1] + cmp r1, #0 + bne 1f + ldr r1,=mm_mastertempo // multiply by master tempo + ldr r1, [r1] // + mul r0, r1 // +// lsr r1, #10 // + + lsl r0, #16+6-10 + b 2f +1: + lsl r0, #16+6 +2: + @ using 60hz vsync for timing +// lsl r0, #16+6 + ldr r1,=mpp_resolution + ldr r1, [r1] + swi SWI_DIVIDE + lsr r0, #1 + mov r1, #MPL_TICKRATE + strh r0, [r5, r1] + bx lr + +#endif + +.pool + +/****************************************************************************** + * mpp_setposition( position ) + * + * Set sequence position. + * Input r5 = layer + ******************************************************************************/ + .thumb_func +mpp_setposition: + + push {lr} + +mpp_setpositionA: + + strb r0, [r5, #MPL_POSITION] + + ldr r1, [r5, #MPL_SONGADR] + mov r3, r1 + add r1, #C_MAS_ORDER @ get sequence entry + ldrb r1, [r1, r0] @ + + cmp r1, #254 + bne .mpsp_skippatt + add r0, #1 + b mpp_setpositionA +.mpsp_skippatt: + + cmp r1, #255 + bne .mpsp_endsong + + @ END OF SONG!!! WOOPHEE!!!! + + + mov r0, #MPL_MODE @mpp_playmode + ldrb r0, [r5, r0] + + cmp r0, #MPP_PLAY_ONCE + bge 1f +@ @ its looping: + b 3f + +1: @ its playing once: + + bl mppStop + mov r0, #MPCB_SONGFINISHED + ldr r2,=mmCallback + ldr r2,[r2] + cmp r2, #0 + beq 3f + ldr r1,=mpp_clayer + ldrb r1, [r1] + bl mpp_call_r2 + +3: + + ldrb r0, [r5, #MPL_ISPLAYING] + cmp r0, #0 + bne 1f + + pop {pc} + +1: + ldr r0, [r5, #MPL_SONGADR] @ set position to 'restart' + ldrb r0, [r0, #C_MAS_REP] + b mpp_setpositionA +.mpsp_endsong: + + mov r0, r1 + + ldr r1, [r5, #MPL_PATTTABLE] + lsl r0, #2 + + @ r1 = pattern address( in table ) + + ldr r1, [r1, r0] + add r1, r3 @ add song address + + @ r1 = pattern address + + ldrb r2, [r1] @ set pattern size + strb r2, [r5, #MPL_NROWS] @ + + mov r2, #0 @ reset tick/row + strh r2, [r5, #MPL_TICK] + strb r2, [r5, #MPL_FPATTDELAY] + strb r2, [r5, #MPL_PATTDELAY] + + mov r0, #MPL_PATTREAD + add r1, #1 + str r1, [r5, r0] @ store pattern data address + + mov r0, #MPL_PLOOP_ADR @ reset pattern loop + str r1, [r5, r0] + mov r0, #0 + strb r0, [r5, #MPL_PLOOP_ROW] + strb r0, [r5, #MPL_PLOOP_TIMES] + + pop {pc} + +//----------------------------------------------------------------------------- +#ifdef SYS_NDS +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppUpdateLayer( layer ) + * + * Update module layer + ******************************************************************************/ + .thumb_func +mppUpdateLayer: + + push {lr} + ldr r1,=mpp_layerp + str r0, [r1] + mov r1, #MPL_TICKRATE + ldrh r1, [r0, r1] + mov r2, #MPL_TICKFRAC + ldrh r3, [r0, r2] + lsl r1, #1 + add r3, r1 + strh r3, [r0, r2] + lsr r3, #16 + beq 1f +2: push {r3} + + bl mppProcessTick + pop {r3} + sub r3, #1 + bne 2b +1: pop {pc} + +/****************************************************************************** + * mmPulse() + * + * NDS Work Routine + ******************************************************************************/ + .global mmPulse + .thumb_func +mmPulse: + + push {lr} + + ldr r0,=mpp_channels // update main layer + ldr r1,=mm_pchannels // + ldr r1,[r1] // + str r1, [r0] // + ldr r0,=mpp_nchannels // + ldr r1,=mm_num_mch // + ldr r1,[r1] // + strb r1, [r0] // + ldr r0,=mpp_clayer // + mov r1, #0 // + strb r1, [r0] // + // + ldr r0,=mmLayerMain // + bl mppUpdateLayer // + + ldr r0,=mpp_channels // update sub layer + ldr r1,=mm_schannels // + str r1, [r0] // + ldr r0,=mpp_nchannels // + mov r1, #MP_SCHANNELS // + strb r1, [r0] // + ldr r0,=mpp_clayer // + mov r1, #1 // + strb r1, [r0] // + // + ldr r0,=mmLayerSub // + bl mppUpdateLayer // + + pop {pc} + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +#ifdef SYS_GBA +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppUpdateSub() + * + * Update sub-module/jingle, this is bad for some reason... + ******************************************************************************/ + .global mppUpdateSub + .thumb_func +mppUpdateSub: + + ldr r0,=mmLayerSub + ldrb r0, [r0, #MPL_ISPLAYING] + cmp r0, #0 + bne .mppus_update + bx lr +.mppus_update: + + ldr r0,=mpp_channels + ldr r1,=mm_schannels + str r1, [r0] + ldr r0,=mpp_nchannels + mov r1, #MP_SCHANNELS + strb r1, [r0] + ldr r0,=mpp_clayer + mov r1, #1 + strb r1, [r0] + + push {lr} + ldr r0,=mmLayerSub + ldr r1,=mpp_layerp + str r0, [r1] + + mov r1, #MPL_TICKRATE + ldrh r1, [r0, r1] + mov r2, #MPL_TICKFRAC + ldrh r3, [r0, r2] + lsl r1, #1 + add r3, r1 + strh r3, [r0, r2] + lsr r3, #16 + beq 1f +2: push {r3} + ldr r1,=mppProcessTick + bl mpp_call_r1 + pop {r3} + sub r3, #1 + bgt 2b +1: pop {pc} + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + +.pool + +//----------------------------------------------------------------------------- +// IWRAM CODE +//----------------------------------------------------------------------------- +#ifdef USE_IWRAM + .SECTION ".iwram", "ax", %progbits + .ALIGN 2 +#endif +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppProcessTick() + * + * Process module tick. + ******************************************************************************/ +.global mppProcessTick @@@@@@@@@@@@@@@@@@ +.thumb_func @@@@ @@@ @@ + @@@ @@ @@@@@@ @@ +mppProcessTick: @@ @@@ @ @@ + @@ @@@@@@@ @@@ + @@@@@@@@@@@@@@@@@ + + add r0,pc,#0 // switch to ARM to preserve regs + bx r0 // +.arm // + stmfd sp!, {lr} // + stmfd sp!, {r4-r10} // + + add r0,pc,#1 // switch back to THUMB + bx r0 +.thumb + + ldr r0,=mpp_layerp // test if module is playing + ldr r0, [r0] // + mov r8, r0 // + ldrb r1, [r0, #MPL_ISPLAYING] // + cmp r1, #0 // + bne 1f // + ldr r1,=.mppt_exit // + mov pc,r1 // +1: + +@--------------------------------------------------- +@ read pattern data +@--------------------------------------------------- + + ldrb r1, [r0, #MPL_PATTDELAY] + cmp r1, #0 + bne .mpp_pt_skippatternread + ldrb r0, [r0, #MPL_TICK] + cmp r0, #0 + bne .mpp_pt_skippatternread + + PROF_START + fjump2 mmReadPattern + //bl mpp_ReadPattern + PROF_END 4 + +@----------------------------------------- +.mpp_pt_skippatternread: + + mov r0, r8 + mov r4, #MPL_MCH_UPDATE + ldr r4, [r0, r4] + +@--------------------------------------------------- +@ loop through module channels +@--------------------------------------------------- + + ldr r7,=mpp_channels + ldr r7, [r7] + mov r0, #0 + mov r10, r0 @ use r10 as channel counter + mov r0, r8 + ldrb r0, [r0, #MPL_TICK] + cmp r0, #0 + bne pchannel_loop_other + +@--------------------------------------------------- +pchannel_loop_first: +@--------------------------------------------------- + lsr r4, #1 + bcc pchannel_empty + fjump2 mmUpdateChannel_T0 +pchannel_empty: + mov r0, #1 + add r10, r0 + add r7, #MCH_SIZE + cmp r4, #0 + bne pchannel_loop_first + b pchannel_loop_finished + +@--------------------------------------------------- +pchannel_loop_other: +@--------------------------------------------------- + lsr r4, #1 + bcc pchannel_empty2 + #ifdef FOO_UC + bl mpp_Update_Channel + #else + fjump2 mmUpdateChannel_TN + #endif + +pchannel_empty2: + mov r0, #1 + add r10, r0 + add r7, #MCH_SIZE + cmp r4, #0 + bne pchannel_loop_other + +pchannel_loop_finished: + +@--------------------------------------------------- +@ loop through active channels +@--------------------------------------------------- + PROF_START + ldr r6,=mm_achannels + ldr r6, [r6] + @ldr r6,=mpp_achannels + mov r4, #0 + +@--------------------------------------------------- +.mpp_pt_achn_loop: +@--------------------------------------------------- + + ldrb r0, [r6, #MCA_TYPE] + cmp r0, #ACHN_DISABLED + beq .mpp_pt_achn_disabled + ldr r0,=mpp_clayer + ldrb r0, [r0] + ldrb r1, [r6, #MCA_FLAGS] + lsr r1, #6 + cmp r1, r0 + bne .mpp_pt_achn_next + + ldr r1,=mpp_vars + ldrb r0, [r6, #MCA_VOLUME] + strb r0, [r1, #MPV_AFVOL] + mov r0, #0 + strh r0, [r1, #MPV_PANPLUS] + + ldr r5, [r6, #MCA_PERIOD] + + bl mpp_Update_ACHN + + b .mpp_pt_achn_next + +@--------------------------------------------------- +.mpp_pt_achn_disabled: +@ mov r0, r4 +@ bl mp_Mixer_StopChannel + +@--------------------------------------------------- +.mpp_pt_achn_next: +@--------------------------------------------------- + + ldrb r0, [r6, #MCA_FLAGS] + mov r1, #MCAF_UPDATED + bic r0, r1 + strb r0, [r6, #MCA_FLAGS] + add r6, #MCA_SIZE + add r4, #1 + ldr r0,=mm_num_ach + ldr r0,[r0] + + cmp r4, r0 +@ cmp r4, #MP_NCHANNELS + bne .mpp_pt_achn_loop +@--------------------------------------------------- + PROF_END 6 + + + + ldr r1,=mppProcessTick_incframe + mov pc,r1 + +.pool + +//----------------------------------------------------------------------------- +// TEXT Code +//----------------------------------------------------------------------------- + .TEXT + .THUMB + .ALIGN 2 +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppProcessTick_incframe [[internal]] + ******************************************************************************/ + .thumb_func +mppProcessTick_incframe: + +@--------------------------------------------------- +@ update tick/row/position +@--------------------------------------------------- + + mov r5, r8 @ get tick# + ldrb r1, [r5, #MPL_TICK] @ .. + add r1, #1 @ increment + + ldrb r2, [r5, #MPL_SPEED] @ compare with speed + cmp r1, r2 @ .. + blt .mppt_continuerow @ if less than, continue this row + + ldrb r2, [r5, #MPL_FPATTDELAY] + cmp r2, #0 + beq .mppt_nofpd + sub r2, #1 + strb r2, [r5, #MPL_FPATTDELAY] + b .mppt_continuerow +.mppt_nofpd: + + mov r1, #0 @ .. otherwise clear tick count + b .mppt_nextrow @ and advance to next row + +.mppt_continuerow: @ continue current row: + strb r1, [r5, #MPL_TICK] @ save tick# + b .mppt_exit @ exit + +.mppt_nextrow: @ advance row + + ldrb r2, [r5, #MPL_PATTDELAY] + cmp r2, #0 + beq .mppt_nopd + sub r2, #1 + strb r2, [r5, #MPL_PATTDELAY] + beq .mppt_nopd + b .mppt_continuerow +.mppt_nopd: + + strb r1, [r5, #MPL_TICK] @ save tick# (0) + ldrb r1, [r5, #MPL_PATTJUMP] + cmp r1, #255 + beq .mppt_no_pj + + mov r2, #255 + strb r2, [r5, #MPL_PATTJUMP] + mov r0, r1 + bl mpp_setposition + + ldrb r1, [r5, #MPL_PATTJUMP_ROW] + cmp r1, #0 + beq .mppt_pj_no_offset + mov r2, #0 + strb r2, [r5, #MPL_PATTJUMP_ROW] + bl mpph_FastForward +.mppt_pj_no_offset: + + b .mppt_exit + +.mppt_no_pj: + + mov r3, #MPL_PLOOP_JUMP + ldrb r1, [r5, r3] + cmp r1, #0 + beq .mppt_no_ploop + mov r1, #0 + strb r1, [r5, r3] + ldrb r1, [r5, #MPL_PLOOP_ROW] + strb r1, [r5, #MPL_ROW] + mov r3, #MPL_PLOOP_ADR + ldr r1, [r5, r3] + + mov r3, #MPL_PATTREAD + str r1, [r5, r3] + b .mppt_exit +.mppt_no_ploop: + ldrb r1, [r5, #MPL_ROW] @ .. + add r1, #1 @ increment + ldrb r2, [r5, #MPL_NROWS] @ + add r2, #1 + cmp r1, r2 @ check with #rows for pattern + bne .mppt_continuepattern @ if !=, then continue playing this pattern + +.mppt_nextposition: @ advance position + + ldrb r0, [r5, #MPL_POSITION] @ increment position + add r0, #1 + + bl mpp_setposition + b .mppt_exit + +.mppt_continuepattern: + + strb r1, [r5, #MPL_ROW] @ save row count + +.thumb_func +.mppt_exit: + + @ switch to arm + ldr r0,=.mppt_exita + bx r0 +.arm +.align 2 +.mppt_exita: + + ldmfd sp!, {r4-r10} + ldmfd sp!, {r0} + bx r0 +.thumb + +.pool + +//----------------------------------------------------------------------------- +// IWRAM CODE +//----------------------------------------------------------------------------- +#ifdef USE_IWRAM + .SECTION ".iwram", "ax", %progbits + .ALIGN 2 +#endif +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mpp_Channel_NewNote() + * + * Process new note. + * Input r7 = pchannel address + ******************************************************************************/ + .global mpp_Channel_NewNote + .thumb_func +mpp_Channel_NewNote: + + @ r7 = pchannel address + push {r4,lr} + + ldrb r0, [r7, #MCH_INST] @ get instrument# + sub r0, #1 + bcc .mppt_skipnna + + bl mpp_Channel_GetACHN + cmp r6, #0 + beq .mppt_alloc_channel + + ldrb r0, [r7, #MCH_INST] @ get instrument# + sub r0, #1 + + mpp_InstrumentPointer + + ldrb r1, [r7, #MCH_BFLAGS] @ fetch NNA + lsr r1, #6 + + beq .mppt_NNA_CUT @ skip if zero + + ldrb r1, [r0, #C_MASI_DCT] @ otherwise check duplicate check type + lsl r1, #32-2 + lsr r1, #32-2 + lsl r1, #1 @ jump to mppt_DCT_TABLE[dct] + add r1, pc + mov pc, r1 + +.mppt_DCT_TABLE: +b .mppt_DCNA +b .mppt_DCT_NOTE +b .mppt_DCT_SAMP +b .mppt_DCT_INST +.mppt_DCT_NOTE: @ DCT note --------------------- + ldrb r1, [r7, #MCH_PNOTE] @ get pattern note + lsl r1, #1 @ translate to real note + add r1, #C_MASI_MAP @ with note/sample map + ldrb r1, [r0, r1] @ r1 = real note + ldrb r2, [r7, #MCH_NOTE] @ compare with last note + cmp r1, r2 @ + beq .mppt_DCA @ equal? perform DCA + b .mppt_DCNA @ otherwise skip + +.mppt_DCT_SAMP: @ DCT sample ------------------- + + // **WARNING: code not functional with new instrument table + ldrb r1, [r7, #MCH_PNOTE] @ get pattern note + lsl r1, #1 @ translate to sample# + add r1, #C_MASI_MAP+1 @ with note/sample map + ldrb r1, [r0, r1] @ r1 = sample# + ldrb r2, [r6, #MCA_SAMPLE] @ compare with achn's sample + cmp r1, r2 @ + beq .mppt_DCA @ equal? perform DCA + b .mppt_DCNA @ otherwise skip + +.mppt_DCT_INST: @ DCT instrument --------------- + ldrb r1, [r7, #MCH_INST] @ load instrument + ldrb r2, [r6, #MCA_INST] @ compare with active inst + cmp r1, r2 @ + bne .mppt_DCNA @ not equal? skip DCA + +.mppt_DCA: @ DUPLICATE CHECK ACTION ------- + ldrb r1, [r0, #C_MASI_DCA] @ read type + cmp r1, #IT_DCA_CUT @ cut? + beq .mppt_NNA_CUT @ branch + cmp r1, #IT_DCA_OFF @ note-off? + beq .mppt_NNA_OFF @ branch + b .mppt_NNA_FADE @ note-fade otherwise + +.mppt_DCNA: + + ldrb r1, [r7, #MCH_BFLAGS] + lsr r1, #6 @ get NNA + lsl r1, #1 @ and jump to + add r1, pc @ NNA_TABLE[NNA] + mov pc, r1 +.mppt_NNA_TABLE: +b .mppt_NNA_CUT +b .mppt_NNA_CONTINUE +b .mppt_NNA_OFF +b .mppt_NNA_FADE + +@--------------------------------------------------------------------------------- +.mppt_NNA_CUT: +@--------------------------------------------------------------------------------- + + #ifdef SYS_NDS // nds supports volume ramping + + ldrb r1, [r6, #MCA_TYPE] + cmp r1, #0 + BEQ .mppt_samechannel + mov r1, #ACHN_BACKGROUND + strb r1, [r6, #MCA_TYPE] + mov r1, #0 + strb r1, [r6, #MCA_VOLUME] + b .mppt_NNA_FINISHED + + #else + b .mppt_samechannel + #endif + +@--------------------------------------------------------------------------------- +.mppt_NNA_CONTINUE: +@--------------------------------------------------------------------------------- + + mov r1, #ACHN_BACKGROUND @ use different channel + strb r1, [r6, #MCA_TYPE] @ set active channel to "background" + b .mppt_NNA_FINISHED @ finished + +@--------------------------------------------------------------------------------- +.mppt_NNA_OFF: +@--------------------------------------------------------------------------------- + + ldrb r1, [r6, #MCA_FLAGS] @ clear KEYON in flags byte + mov r2, #MCAF_KEYON + bic r1, r2 + + strb r1, [r6, #MCA_FLAGS] + mov r1, #ACHN_BACKGROUND @ set type to "background" + strb r1, [r6, #MCA_TYPE] + b .mppt_NNA_FINISHED @ finished + +@--------------------------------------------------------------------------------- +.mppt_NNA_FADE: +@--------------------------------------------------------------------------------- + + ldrb r1, [r6, #MCA_FLAGS] @ set NOTE FADE in flags byte + mov r2, #MCAF_FADE + orr r1, r2 + strb r1, [r6, #MCA_FLAGS] + mov r1, #ACHN_BACKGROUND @ set type to "background" + strb r1, [r6, #MCA_TYPE] @ + +.mppt_NNA_FINISHED: + +.mppt_alloc_channel: + + mov r4, r6 + + ldr r1,=mmAllocChannel + jump1 @ find new active channel + strb r0, [r7, #MCH_ALLOC] @ save number + + #ifdef SYS_NDS + + cmp r4, #0 + beq .mppt_samechannel + + mov r1, #MCA_SIZE @ copy data from previous channel + mul r0, r1 @ (for volume ramping wierdness) + ldr r1,=mm_achannels @ + ldr r1,[r1] @ + add r0, r1 @ + @ + mov r2, #MCA_SIZE/4 +1: ldmia r4!, {r1} + stmia r0!, {r1} + sub r2, #1 + bne 1b + +/* ldr r1, [r4, #MCA_FADE] @ + str r1, [r0, #MCA_FADE] @ + ldr r1, [r4, #MCA_ENVC_PAN] @ + str r1, [r0, #MCA_ENVC_PAN] @ + ldr r1, [r4, #MCA_AVIB_DEP] @ + str r1, [r0, #MCA_AVIB_DEP] @ + ldrb r1, [r4, #MCA_FLAGS] @ + strb r1, [r0, #MCA_FLAGS] @ + ldrb r1, [r4, #MCA_VOLUME] + strb r1, [r0, #MCA_VOLUME] + ldrb r1, [r4, #MCA_PANNING] + strb r1, [r0, #MCA_PANNING] + ldrb r1, [r4, #MCA_SAMPLE] + strb r1, [r0, #MCA_SAMPLE] + ldrb r1, [r4, #MCA_INST] + strb r1, [r0, #MCA_INST]*/ + + #endif + +.mppt_samechannel: + +.mppt_skipnna: + pop {r4} + pop {r3} + bx r3 + +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------------------------ +mpp_Channel_GetACHN: +@------------------------------------------------------------------------------------------------------ + + @ gets the active channel pointer + @ and stores in r6 + @ gives 0 if N/A + + ldrb r0, [r7, #MCH_ALLOC] + cmp r0, #255 + bge 1f + ldr r6,=mm_achannels + ldr r6,[r6] + mov r1, #MCA_SIZE + mul r0, r1 + add r6, r0 + bx lr + +1: mov r6, #0 + bx lr +.pool + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------------------- +mpp_Update_ACHN: +@---------------------------------------------------------------------------------------------------- + +@ r5 = affected period +@ r6 = achannel address + + push {lr} @ enter subroutine + +@ check updated flag & exit if already updated + + ldrb r0, [r6, #MCA_FLAGS] + mov r1, #MCAF_UPDATED + tst r0, r1 + beq .mpp_achn_update + pop {pc} + +@-------------------------------------------- + + .global mpp_Update_ACHN_notest + .thumb_func +@---------------------------------------------------------------------------------------------------- +mpp_Update_ACHN_notest: +@---------------------------------------------------------------------------------------------------- + push {lr} + +.mpp_achn_update: + +@------------------------------------------------------------------------ +@ Envelope Processing +@------------------------------------------------------------------------ + + ldrb r0, [r6, #MCA_INST] + sub r0, #1 + bCS 1f + b .mppt_achn_noinst +1: mpp_InstrumentPointer + +@ get envelope flags + + mov r1, r0 + ldrb r2, [r1, #C_MASI_ENVFLAGS] + add r1, #C_MASI_ENVELOPES + + lsr r2, #1 @ shift out volume envelope bit + bcc .mppt_no_volenv + + ldrb r3, [r6, #MCA_FLAGS] + lsr r3, #6 + + bcs .mppt_achn_ve_enabled + ldrb r0, [r1] + add r1, r0 + b .mppt_no_volenv +.mppt_achn_ve_enabled: + + push {r1, r2} + + ldrh r0, [r6, #MCA_ENVC_VOL] + mov r2, r1 + ldrb r1, [r6, #MCA_ENVN_VOL] + bl mpph_ProcessEnvelope + strb r1, [r6, #MCA_ENVN_VOL] + strh r0, [r6, #MCA_ENVC_VOL] + mov r1, r3 + + cmp r2, #1 + bne .mpph_volenv_notend + ldrb r0, [r6, #MCA_FLAGS] + + mov r3, r8 @ stupid xm doesn't fade out at envelope end + ldrb r3, [r3, #MPL_FLAGS] + lsr r3, #C_FLAGS_XS + + mov r3, #MCAF_ENVEND + bcs 1f + mov r3, #MCAF_ENVEND+MCAF_FADE +1: + orr r0, r3 + strb r0, [r6, #MCA_FLAGS] +.mpph_volenv_notend: + + cmp r2, #1 + blt .mpph_volenv_normal + + @ check keyon and turn on fade... + ldrb r0, [r6, #MCA_FLAGS] + mov r2, #MCAF_KEYON + tst r0, r2 + bne .mpph_volenv_normal +.mpph_volenv_notefade: + mov r2, #MCAF_FADE + orr r0, r2 + strb r0, [r6, #MCA_FLAGS] + +.mpph_volenv_normal: + + ldr r0,=mpp_vars + ldrb r2, [r0, #MPV_AFVOL] + mul r2, r1 + lsr r2, #6+6 + strb r2, [r0, #MPV_AFVOL] + pop {r1, r2} + ldrb r0, [r1] + add r1, r0 + b .mppt_has_volenv +.mppt_no_volenv: + + ldrb r0, [r6, #MCA_FLAGS] + mov r3, #MCAF_ENVEND + orr r0, r3 + mov r3, #MCAF_KEYON + tst r0, r3 + bne .mppt_has_volenv + mov r3, #MCAF_FADE + orr r0, r3 + strb r0, [r6, #MCA_FLAGS] + + mov r0, r8 @ check XM MODE and cut note + ldrb r0, [r0, #MPL_FLAGS] + lsr r0, #C_FLAGS_XS + bcc .mppt_has_volenv + mov r0, #0 + strh r0, [r6, #MCA_FADE] +.mppt_has_volenv: + + lsr r2, #1 + bcc .mppt_no_panenv + push {r1, r2} + ldrh r0, [r6, #MCA_ENVC_PAN] + mov r2, r1 + ldrb r1, [r6, #MCA_ENVN_PAN] + bl mpph_ProcessEnvelope + strb r1, [r6, #MCA_ENVN_PAN] + strh r0, [r6, #MCA_ENVC_PAN] + mov r1, r3 + + ldr r0,=mpp_vars + mov r3, #MPV_PANPLUS + ldrsh r2, [r0,r3] + lsr r1, #4 + sub r1, #128 + add r2, r1 + strh r2, [r0,r3] + pop {r1, r2} +.mppt_no_panenv: + + lsr r2, #1 + bcc .mppt_no_pitchenv + ldrb r0, [r1, #C_MASIE_FILTER] + cmp r0, #0 + bne .mppt_no_pitchenv + push {r1, r2} + ldrh r0, [r6, #MCA_ENVC_PIC] + mov r2, r1 + ldrb r1, [r6, #MCA_ENVN_PIC] + bl mpph_ProcessEnvelope + strb r1, [r6, #MCA_ENVN_PIC] + strh r0, [r6, #MCA_ENVC_PIC] + mov r1, r3 + lsr r1, #3 + sub r1, #255 + mov r0, r5 + sub r1, #1 + bmi .mppt_pitchenv_minus +#ifdef USE_IWRAM + ldr r2,=mpph_LinearPitchSlide_Up + jump2 +#else + bl mpph_LinearPitchSlide_Up +#endif + b .mppt_pitchenv_plus +.mppt_pitchenv_minus: + neg r1, r1 +#ifdef USE_IWRAM + ldr r2,=mpph_LinearPitchSlide_Down + jump2 +#else + bl mpph_LinearPitchSlide_Down +#endif +.mppt_pitchenv_plus: + mov r5, r0 + pop {r1, r2} +.mppt_no_pitchenv: + + ldrb r0, [r6, #MCA_FLAGS] + mov r1, #MCAF_FADE + tst r0, r1 + beq .mppt_achn_nofade + ldrb r0, [r6, #MCA_INST] + sub r0, #1 + + mpp_InstrumentPointer + ldrb r0, [r0, #C_MASI_FADE] + + ldrh r1, [r6, #MCA_FADE] + + sub r1, r0 + bcs .mppt_achn_fadeout_clip + mov r1, #0 +.mppt_achn_fadeout_clip: + strh r1, [r6, #MCA_FADE] + +.mppt_achn_nofade: + +.mppt_achn_keyon: + + +@---------------------------------------------------------------------------------- +@ *** PROCESS AUTO VIBRATO +@---------------------------------------------------------------------------------- + + ldrb r0, [r6, #MCA_SAMPLE] + sub r0, #1 + bcc .mppt_achn_nostart @ no sample!! + + @bl mpp_SamplePointer + mpp_SamplePointer + ldrh r1, [r0, #C_MASS_VIR] @ get av-rate + cmp r1, #0 @ 0? + beq .mppt_av_disabled @ if 0 then its disabled + ldrh r2, [r6, #MCA_AVIB_DEP] @ get depth counter + add r2, r1 @ add rate + lsr r1, r2, #15 @ check for 15-bit overflow + beq .mppt_av_depclip @ .. + + ldr r2,=32768 @ and clamp to 32768 +.mppt_av_depclip: + strh r2, [r6, #MCA_AVIB_DEP] @ save depth counter + ldrb r1, [r0, #C_MASS_VID] @ get av-depth + mul r1, r2 @ multiply + + ldrb r3, [r6, #MCA_AVIB_POS] @ get table position + ldrb r2, [r0, #C_MASS_VIS] @ get av-speed + add r3, r2 @ add to position + lsl r3, #32-8 @ wrap position to 0->255 + lsr r3, #32-8 @ .. + strb r3, [r6, #MCA_AVIB_POS] @ save position + ldr r2,=mpp_TABLE_FineSineData @ get table pointer + ldrsb r2, [r2, r3] @ load table value at position + mul r2, r1 @ multiply with depth + asr r2, #23 @ shift value + bmi .mppt_av_minus @ and perform slide... +.mppt_av_plus: @ --slide up + mov r1, r2 @ r1 = slide value + mov r0, r5 @ r0 = frequency +#ifdef USE_IWRAM + fjump2 mpph_PitchSlide_Up +#else + bl mpph_PitchSlide_Up @ pitch slide +#endif + b .mppt_av_finished @ +.mppt_av_minus: @ --slide down + neg r1, r2 @ r1 = slide value + mov r0, r5 @ r0 = frequency +#ifdef USE_IWRAM + ldr r2,=mpph_PitchSlide_Down + jump2 +#else + bl mpph_PitchSlide_Down @ pitch slide +#endif + +.mppt_av_finished: + mov r5, r0 @ affect frequency +.mppt_av_disabled: + +@--------------------------------------------------------------------------------- + +.mppt_achn_noinst: + + push {r4} + mov r0, #MIXER_CHN_SIZE + mul r4, r0 + @ldr r0,=mp_channels +@ ldr r0,=mm_mixchannels +@ ldr r0,[r0] + GET_MIXCH r0 + add r4, r0 + + @ *** UPDATE MIXING INFORMATION + + ldrb r0, [r6, #MCA_FLAGS] @ read flags + mov r1, #MCAF_START @ test start bit + tst r0, r1 @ .. + beq .mppt_achn_nostart @ +.mppt_achn_start: @ START NOTE + bic r0, r1 @ clear bit + strb r0, [r6, #MCA_FLAGS] @ save flags + ldrb r0, [r6, #MCA_SAMPLE] @ get sample # + + sub r0, #1 @ .. + bcc .mppt_achn_nostart @ quit if invalid + @bl mpp_SamplePointer @ get sample address + mpp_SamplePointer + + ldrh r3, [r0, #C_MASS_MSLID] + + add r1,r3,#1 @ msl id == 0xFFFF? + lsr r1, #17 + + bcc .mppt_achn_msl_sample + +.mppt_achn_direct_sample: @ then sample follows + + add r0, #12 + +//------------------------------------------------ +#ifdef SYS_GBA +// ldr r1, [r0,#C_SAMPLE_LEN] @ setup mixer (GBA) +// lsl r1, #MP_SAMPFRAC +// str r1, [r4,#MIXER_CHN_LEN] +// ldr r1, [r0,#C_SAMPLE_LOOP] +// str r1, [r4,#MIXER_CHN_LOOP] + add r0, #C_SAMPLE_DATA + str r0, [r4,#MIXER_CHN_SRC] + +#else +//------------------------------------------- + + ldr r1,=0x2000000 + sub r0, r1 + str r0, [r4, #MIXER_CHN_SAMP] + ldrb r1, [r4, #MIXER_CHN_CNT] + mov r0, #MIXER_CF_START + orr r1, r0 + strb r1, [r4, #MIXER_CHN_CNT] + +#endif +//------------------- + + b .mppt_achn_gotsample +.mppt_achn_msl_sample: @ otherwise get from solution + + #ifdef SYS_GBA + + ldr r2,=mp_solution + ldr r2, [r2] + mov r1, r2 + add r1, #12 + lsl r3, #2 + ldr r1, [r1, r3] + add r1, #8 + add r0, r1, r2 + + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ NOTICE, USE LDM HERE + +// ldr r1, [r0,#C_SAMPLE_LEN] @ setup mixer (GBA) +// lsl r1, #MP_SAMPFRAC +// str r1, [r4,#MIXER_CHN_LEN] +// ldr r1, [r0,#C_SAMPLE_LOOP] +// str r1, [r4,#MIXER_CHN_LOOP] + add r0, #C_SAMPLE_DATA + str r0, [r4,#MIXER_CHN_SRC] + + #endif + + #ifdef SYS_NDS + + ldr r2,=mmSampleBank @ get samplebank pointer + ldr r2, [r2] + lsl r3, #2 @ add msl_id *4 + ldr r1, [r2, r3] + + lsl r1, #8 @ mask out counter value + lsr r1, #8 + add r1, #8 + + str r1, [r4,#MIXER_CHN_SAMP] + ldrb r1, [r4,#MIXER_CHN_CNT] // read control **CNT was cleared, no need to read it + mov r0, #MIXER_CF_START // set start bit + orr r1, r0 + strb r1, [r4,#MIXER_CHN_CNT] // save control + + #endif + +.mppt_achn_gotsample: + ldr r1,=mpp_vars + ldrb r1, [r1, #MPV_SAMPOFF] +#ifdef SYS_GBA + lsl r1, #MP_SAMPFRAC+8 + str r1, [r4, #MIXER_CHN_READ] +#else + str r1, [r4, #MIXER_CHN_READ] +#endif + +.mppt_achn_nostart: + @ set pitch + + ldrb r0, [r6, #MCA_SAMPLE] @ get sample# + sub r0, #1 @ .. + bcc .mppt_achn_setvolumeA + @bl mpp_SamplePointer @ quit if invalid + mpp_SamplePointer + push {r0} + + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_SS + bcc .mppt_achn_amigafreqs +.mppt_achn_linearfreqs: + + ldrh r0, [r0, #C_MASS_FREQ] @ get C5SPEED + LSL R0, #2 + lsr r1, r5, #8 @ do some stuff... + mul r1, r0 @ ... period * freq? + + lsr r1, #8 + + ldr r0,=mpp_clayer + ldrb r0, [r0] + cmp r0, #0 + bne 1f + ldr r0,=mm_masterpitch + ldr r0, [r0] + mul r1, r0 + lsr r1, #10 +1: + + #ifdef SYS_GBA + + +// ldr r0,=mm_freqscalar +// ldr r0, [r0] + ldr r0,=(4096*65536)/15768 + mul r0, r1 + lsr r0, #16 + str r0, [r4, #MIXER_CHN_FREQ] + + #else + + ldr r0,=MIXER_SCALE + mul r0, r1 + lsr r0, #16+1 + strh r0, [r4, #MIXER_CHN_FREQ] + + //strh r1, [r4, #MIXER_CHN_FREQ] + #endif + + b .mppt_achn_setvolume + +.mppt_achn_amigafreqs: + ldr r0,=MOD_FREQ_DIVIDER_PAL + movs r1, r5 + + beq .mppt_achn_setvolume @ 0 is a bad period + swi SWI_DIVIDE + + ldr r1,=mpp_clayer + ldrb r1, [r1] + cmp r1, #0 + bne 1f + ldr r1,=mm_masterpitch + ldr r1, [r1] + mul r0, r1 + lsr r0, #10 +1: + + #ifdef SYS_GBA + +// ldr r1,=mm_freqscalar +// ldr r1,[r1] + ldr r1,=(4096*65536)/15768 + mul r0, r1 + lsr r0, #16 + + str r0, [r4, #MIXER_CHN_FREQ] + #else +// mov r1, r0 +// ldr r0,=16756991 @ calculate ds mixer timing +// swi SWI_DIVIDE +// neg r0,r0 + //lsr r0, #5 + ldr r1,=MIXER_SCALE + mul r0, r1 + lsr r0, #16+1 + strh r0, [r4, #MIXER_CHN_FREQ] + #endif + +@---------------------------------------------------------------------------------------------------- +.mppt_achn_setvolume: +@---------------------------------------------------------------------------------------------------- + + @ set volume + + pop {r0} + @ <-- stepped oct 28, 3:27pm + ldrb r3, [r0, #C_MASS_GV] @ SV, 6-bit + ldrb r0, [r6, #MCA_INST] + sub r0, #1 + bcs 1f + +.thumb_func +.mppt_achn_setvolumeA: + mov r1, #0 + b .mppt_achn_badinstrument +1: + mpp_InstrumentPointer + ldrb r0, [r0, #C_MASI_GVOL] @ IV, 7-bit + mul r3, r0 + + ldr r1,=mpp_vars + ldrb r0, [r1, #MPV_AFVOL] @ ((CV*VOL)/32*VEV/64) 7-bit + + mul r3, r0 + + mov r1, r8 @ get global vollume + ldrb r0, [r1, #MPL_FLAGS] + lsr r0, #4 + ldrb r0, [r1, #MPL_GV] @ .. 7-bit + + bcc 1f + lsl r0, #1 @ xm mode global volume is only 0->64, shift to 0->128 + +1: mul r3, r0 @ multiply + + lsr r3, #10 + + ldrh r0, [r6, #MCA_FADE] + + + mul r3, r0 + + lsr r3, r3, #10 + + mov r0, r8 + mov r1, #MPL_VOLUME + ldrh r0, [r0, r1] + mul r3, r0 + +//------------------------------------------------ +#ifdef SYS_NDS + lsr r1, r3, #19-3-5 ///#19-3 (new 16-bit levels!) + ldr r3,=65535 //2047 + cmp r1, r3 @ clip values over 255 + blt 1f + mov r1, r3 +1: +.mppt_achn_badinstrument: +// lsr r3, r1, #3 (new 16-bit levels!) + lsr r3, r1, #8 + strb r3, [r6, #MCA_FVOL] + +#else + + lsr r1, r3, #19 + cmp r1, #255 @ clip values over 255 + blt 1f + mov r1, #255 +1: +.mppt_achn_badinstrument: + strb r1, [r6, #MCA_FVOL] + +#endif + + cmp r1, #0 + bne .mppt_achn_audible + + #ifdef SYS_NDS // nds has volume ramping! + + ldrb r3, [r6, #MCA_TYPE] + cmp r3, #ACHN_BACKGROUND + bne 1f + ldrb r3, [r6, #MCA_VOLUME] + cmp r3, #0 + bne 1f + ldrh r3, [r4, #MIXER_CHN_CVOL] + cmp r3, #0 + beq .mppt_achn_not_audible + #endif + +1: ldrb r3, [r6, #MCA_FLAGS] + mov r2, #MCAF_ENVEND + tst r3, r2 + beq .mppt_achn_audible + mov r2, #MCAF_KEYON + tst r3, r2 + bne .mppt_achn_audible + +// #ifdef SYS_NDS +// ldrh r3, [r4, #MIXER_CHN_CVOL] // nds has volume ramping!! +// cmp r3, #0 +// bne .mppt_achn_audible +// #endif + +.mppt_achn_not_audible: + @ STOP CHANNEL + +#ifdef SYS_GBA + ldr r0,=1<<31 + str r0,[r4,#MIXER_CHN_SRC] @ stop mixer channel +#else + mov r0,#0 + str r0,[r4,#MIXER_CHN_SAMP] @ stop mixer channel +#endif + + ldrb r3, [r6, #MCA_TYPE] + cmp r3, #ACHN_FOREGROUND + bne .mpp_achn_noparent + ldrb r1, [r6, #MCA_PARENT] + mov r3, #MCH_SIZE + mul r1, r3 + ldr r0,=mpp_channels + ldr r0, [r0] + add r0, r1 + mov r1, #255 + strb r1, [r0, #MCH_ALLOC] +.mpp_achn_noparent: + + mov r1, #ACHN_DISABLED + strb r1, [r6, #MCA_TYPE] + b .mpp_achn_updated +.mppt_achn_audible: + +#ifdef SYS_NDS + + strh r1, [r4, #MIXER_CHN_VOL] + +#else + + strb r1, [r4, #MIXER_CHN_VOL] + +#endif + +#ifdef SYS_GBA // check if mixer channel has ended + + ldr r0, [r4, #MIXER_CHN_SRC] + asr r0, #31 + beq 1f + +#else + + ldr r0, [r4, #MIXER_CHN_SAMP] + lsl r0, #8 + bne 1f + +#endif + + ldrb r3, [r6, #MCA_TYPE] + cmp r3, #ACHN_FOREGROUND + bne 2f + + ldrb r1, [r6, #MCA_PARENT] // stop channel if channel ended + mov r3, #MCH_SIZE + mul r1, r3 + ldr r0,=mpp_channels + ldr r0, [r0] + add r0, r1 + mov r1, #255 + strb r1, [r0, #MCH_ALLOC] +2: + +#ifdef SYS_GBA + ldr r0,=1<<31 + str r0,[r4,#MIXER_CHN_SRC] @ stop mixer channel +#else + mov r0,#0 + str r0,[r4,#MIXER_CHN_SAMP] @ stop mixer channel +#endif + + mov r1, #ACHN_DISABLED + strb r1, [r6, #MCA_TYPE] + b .mpp_achn_updated + + @ set panning +1: ldr r1,=mpp_vars + mov r3, #MPV_PANPLUS + ldrsh r0, [r1,r3] + ldrb r1, [r6, #MCA_PANNING] + + add r1, r0 + + cmp r1, #0 + bge .mpp_achn_clippan1 + mov r1, #0 +.mpp_achn_clippan1: + cmp r1, #255 + ble .mpp_achn_clippan2 + mov r1, #255 +.mpp_achn_clippan2: + + #ifdef SYS_NDS + lsr r1, #1 + ldrb r0, [r4, #MIXER_CHN_CNT] + lsr r0, #7 + lsl r0, #7 + orr r0, r1 + strb r0, [r4, #MIXER_CHN_CNT] + #endif + + #ifdef SYS_GBA + strb r1, [r4, #MIXER_CHN_PAN] + #endif + + +.mpp_achn_updated: + pop {r4} + pop {r0} + bx r0 + //pop {pc} @ exit +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------- +mpph_ProcessEnvelope: @ params={count,node,address} +@------------------------------------------------------------------------- + +@ processes the envelope at
+@ returns: +@ r0=count +@ r1=node +@ r2=exit_code +@ r3=value*64 + + push {r4,r5} + +@ get node and base + lsl r4, r1, #2 + add r4, #C_MASIE_NODES + add r4, r2 + + ldrh r3, [r4, #2] + lsl r3, #32-7 + lsr r3, #32-7-6 + +@ check for zero count + + cmp r0, #0 + bne .mpph_pe_between +.mpph_pe_new: + +@ process envelope loop + + ldrb r5, [r2, #C_MASIE_LEND] + cmp r1, r5 + bne 1f + ldrb r1, [r2, #C_MASIE_LSTART] + mov r2, #2 + b .mpph_pe_exit + +@ process envelope sustain loop + +1: ldrb r5, [r6, #MCA_FLAGS] + lsr r5, #1 @ locked + bcc 1f + ldrb r5, [r2, #C_MASIE_SEND] + cmp r1, r5 + bne 1f + ldrb r1, [r2, #C_MASIE_SSTART] + mov r2, #0 + b .mpph_pe_exit + +@ check for end + +1: ldrb r5, [r2, #C_MASIE_NODEC] + sub r5, #1 + cmp r1, r5 + bne .mpph_count + mov r2, #2 + b .mpph_pe_exit + +.mpph_pe_between: + +@ delta * count +@ formula : y = base*2^6 + ----------------- +@ 2^3 + mov r5, #0 + ldrsh r5, [r4,r5] + mul r5, r0 + asr r5, #3 + add r3, r5 + +.mpph_count: + +@ increment count and check if == read count + + add r0, #1 + ldrh r5, [r4, #2] + lsr r5, #7 + cmp r0, r5 + bne .mpph_pe_exit + +@ increment node and reset counter + + mov r0, #0 + add r1, #1 + +.mpph_pe_exit: + + pop {r4,r5} + bx lr +.pool + +/* +.align 2 +.thumb_func +@-------------------------------------------------------------------------------------------- +mpp_Alloc_Channel: +@-------------------------------------------------------------------------------------------- + + @ find a channel to use + @ returns invalid channel if none available + push {r4,r5} @ preserve reg(s) + ldr r5,=mm_ch_mask + ldr r5, [r5] + + @ldr r1,=mpp_achannels @ load pointer + ldr r1,=mm_achannels + ldr r1,[r1] + mov r0, #0 @ load counter + mov r2, #255 @ r2 = MAXVOL+1 (highest) + add r2, #1 + mov r3, #255 @ r3 = 255 (none found) + b .mppac_start + +.mppac_next: + add r1, #MCA_SIZE @ change pointer + add r0, #1 @ count +.mppac_start: + lsr r5, #1 + bcs .mppac_check + bne .mppac_next +.mppac_end: + mov r0, r3 @ if no disabled channels are found, use lowest volume channel +.mppac_found: + + pop {r4,r5} + bx lr + +.mppac_check: + ldrb r4, [r1, #MCA_TYPE] @ check active channel type + cmp r4, #ACHN_DISABLED @ disabled? + beq .mppac_found @ if so, use this channel + cmp r4, #ACHN_BACKGROUND @ check if its a background channel + bne .mppac_next + + ldrb r4, [r1, #MCA_FVOL] @ compare volumes + cmp r4, r2 @ + bge .mppac_next + mov r3, r0 @ save channel# + mov r2, r4 @ and volume + b .mppac_next +*/ + +.pool + +@........................................................................................ + +.thumb_func +mpp_PatternPointer: + mov r1, r8 + ldr r2,[r1,#MPL_SONGADR] + ldr r1,[r1,#MPL_PATTTABLE] + lsl r0, #2 + ldr r0,[r1,r0] + add r0, r2 + bx lr +.pool +#ifdef FOO_UC +.align 2 +.thumb_func +mpp_GetPeriod: + @ r0 = note + @ r2 = tuning + @ CLOBBERS R1,R3 + @ RETURN + @ r0 = IT/S3M PERIOD + + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_SS + bcs .mpp_gp_linear +.mpp_gp_amiga: + + mov r3, r0 + ldr r0,=note_table_mod + ldrb r1, [r0, r3] + sub r0, #3*10 + lsr r3, #2 + ldrb r0, [r0, r3] + + @ r0 = octave + @ r1 = note + lsl r1, #1 + ldr r3,=ST3_FREQTABLE + ldrh r1, [r3, r1] + + ldr r3,=133808 + mul r1, r3 + lsr r1, r0 + + lsr r0, r1, #3 + mov r1, r2 + + swi SWI_DIVIDE + lsl r0, #3 + + bx lr + +.mpp_gp_linear: + ldr r1,=IT_PitchTable + lsl r0, #2 + ldr r0, [r1, r0] + + bx lr + +#endif + +@============================================================================= +@ EFFECT MEMORY +@============================================================================= + +.text + +mpp_effect_memmap_xm: +.byte 0,0,0,0,2,3,4,0,0,5,0,6,7,0,0,8,9,10,11,0,0,0,0,12,0,0,0,0,0,0,13 +@ /,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q, R, S,T,U,V,W, X,Y,Z,0,1,2,3 + +.equ MPP_XM_VFX_MEM_VS, 12 @ $ud +.equ MPP_XM_VFX_MEM_FVS, 13 @ $ud +.equ MPP_XM_VFX_MEM_GLIS, 14 @ $0x +.equ MPP_XM_VFX_MEM_PANSL, 7 @ $lr + +mpp_effect_memmap_it: +.byte 0,0,0,0,2,3,3,0,0,4,5,2,2,0,6,7,8,9,10,11,12,0,0,13,0,14,0 +@ /,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R, S, T, U,V,W, X,Y, Z +mpp_veffect_memmap_it: + +.equ MPP_IT_VFX_MEM, 14 +.equ MPP_GLIS_MEM, 0 +.equ MPP_IT_PORTAMEM, 2 + + +@ 0 means custom behavior, or disabled + +.align 2 +.thumb_func +@----------------------------------------------------------------------------- +mpp_Channel_ExchangeMemory: +@----------------------------------------------------------------------------- + + @ r0 = effect# + @ r1 = param + +@ check flags for XM mode + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_XS + bcs 1f + +@ IT effects + + ldr r2,=mpp_effect_memmap_it + b 2f + +1: +@ XM effects + + ldr r2,=mpp_effect_memmap_xm +2: ldrb r2, [r2, r0] + sub r2, #1 + bcc 3f + +@ if param=0 then load memory value, otherwise save param to memory + + add r2, #MCH_MEMORY + cmp r1, #0 + bne 1f + ldrb r1, [r7, r2] + strb r1, [r7, #MCH_PARAM] +1: strb r1, [r7, r2] + +3: bx lr + +@---------------------------------------------------------- +mpp_Channel_ExchangeGxx: +@---------------------------------------------------------- + + @ r1 = param + + + +/****************************************************************************** + * + * Volume Commands + * + ******************************************************************************/ + + + +/****************************************************************************** + * mpp_Process_VolumeCommand() + * + * Process volume command + ******************************************************************************/ + .global mpp_Process_VolumeCommand + .thumb_func +mpp_Process_VolumeCommand: + + mov r0, r8 + ldrb r2, [r0, #MPL_TICK] + ldr r0, [r0, #MPL_SONGADR] + ldrb r0, [r0, #C_MAS_FLAGS] + lsr r0, #4 + ldrb r0, [r7, #MCH_VOLCMD] + bcc .mppuv_it + b .mppuv_xm +.mppuv_it: + +@ determine which command to use + + cmp r0, #64 + ble .mppuv_setvol + cmp r0, #84 + ble .mppuv_fvol + cmp r0, #104 + ble .mppuv_volslide + cmp r0, #124 + ble .mppuv_porta + cmp r0, #192 + ble .mppuv_panning + cmp r0, #202 + ble .mppuv_glissando + cmp r0, #212 + ble .mppuv_vibrato +.mppuv_exit1: + bx lr + +.align 2 +@----------------------------------------------------------------------------------- +.mppuv_setvol: @ SET VOLUME +@----------------------------------------------------------------------------------- + +@ sets volume on tick0 + + cmp r2, #0 + bne .mppuv_setvol_exit + strb r0, [r7, #MCH_VOLUME] +.mppuv_setvol_exit: + bx lr @ exit + +.align 2 +@----------------------------------------------------------------------------------- +.mppuv_fvol: @ FINE VOLUME SLIDE UP/DOWN +@----------------------------------------------------------------------------------- + + cmp r2, #0 @ only slide on tick0 + bne .mppuv_exit1 @ .. + ldrb r1, [r7, #MCH_VOLUME] @ load channel volume + mov r2, #MCH_MEMORY+MPP_IT_VFX_MEM + cmp r0, #75 @ check slide direction + bge .mppuv_fvoldown @ jump to slide down if value is 75+ (75-84 is slide down) +.mppuv_fvolup: @ ------ slide up ---------- + sub r0, #65 @ 65->74 , 0->9 +.mppuv_volup: @ ** entry for volume slide up + bne 1f @ is value 0? + ldrb r0, [r7, r2] @ then fetch value from memory +1: strb r0, [r7, r2] @ save value +.mppuv_volupA: + add r1, r0 @ add to volume + cmp r1, #64 @ clamp to 0->64 + blt .mppuv_fvol_exit @ .. + mov r1, #64 @ .. + b .mppuv_fvol_exit @ .. +.mppuv_fvoldown: @ ------ slide down -------- + sub r0, #75 @ 75->84 , 0->9 +.mppuv_voldown: @ ** entry for volume slide down + bne 1f @ is value 0? + ldrb r0, [r7, r2] @ then fetch value from memory +1: strb r0, [r7, r2] @ save value +.mppuv_voldownA: + sub r1, r0 @ subtract from volume + bcs .mppuv_fvol_exit @ check overflow and clamp + mov r1, #0 @ .. +.mppuv_fvol_exit: @ .. + strb r1, [r7, #MCH_VOLUME] @ store volume +.mppuv_exit2: + bx lr @ exit function + +.align 2 +@---------------------------------------------------------------------------------- +.mppuv_volslide: @ VOLUME SLIDE UP/DOWN +@---------------------------------------------------------------------------------- + + cmp r2, #0 @ only slide on other ticks + beq .mppuv_exit1 @ .. + ldrb r1, [r7, #MCH_VOLUME] @ get volume + cmp r0, #95 @ check slide direction + bge .mppuv_vs_down +.mppuv_vs_up: @ slide up... + mov r2, #MCH_MEMORY+MPP_IT_VFX_MEM + sub r0, #85 @ 85->94 , 0->9 + b .mppuv_volup @ branch to function (use fvol code) + +.mppuv_vs_down: @ slide down... + mov r2, #MCH_MEMORY+MPP_IT_VFX_MEM + sub r0, #95 @ 95->104 , 0->9 + b .mppuv_voldown @ branch to function (use fvol code) + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_porta: @ PORTAMENTO UP/DOWN +@--------------------------------------------------------------------------------------- + + cmp r2, #0 @ only slide on other ticks + beq .mppuv_exit2 + + push {lr} @ save return address + mov r1, r0 @ get period value + mov r0, #MCH_PERIOD + ldr r0, [r7, r0] + + cmp r1, #115 @ check slide direction + bge .mppuv_porta_up +.mppuv_porta_down: + sub r1, #105 @ map value 0->9 + lsl r1, #2 @ volume command slides are + bne 1f + ldrb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] +1: strb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + bl mpph_PitchSlide_Down @ equal to normal slides *4 + b .mppuv_porta_set + +.mppuv_porta_up: + sub r1, #115 @ slide up... + lsl r1, #2 + bne 1f + ldrb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] +1: strb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + bl mpph_PitchSlide_Up + +.mppuv_porta_set: + mov r2, #MCH_PERIOD @ store new period + ldr r1, [r7, r2] + str r0, [r7, r2] + sub r0, r1 @ and edit temp period + add r5, r0 + + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_panning: @ SET PANNING +@--------------------------------------------------------------------------------------- + + cmp r2, #0 @ only set on tick 0 + bne .mppuv_exit1 @ .. + sub r0, #128 @ map to 0->64 + lsl r0, #2 + cmp r0, #255 + blt .mppuv_p_store + mov r0, #255 +.mppuv_p_store: + strb r0, [r7, #MCH_PANNING] @ save to active channel +.mppuv_p_exit: + bx lr @ exit + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_glissando: @ GLISSANDO +@--------------------------------------------------------------------------------------- + + cmp r2, #0 + beq .mppuv_p_exit + + sub r0, #193 + ldr r1,=vcmd_glissando_table + ldrb r0, [r1, r0] + + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_GS + bcs 2f +@ single gxx + + cmp r0, #0 + beq 1f + ldrb r0, [r7, #MCH_MEMORY+MPP_GLIS_MEM] +1: strb r0, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + b .mppe_glis_ot + +2: @ shared gxx + + cmp r0, #0 + beq 1f + ldrb r0, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] +1: strb r0, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + strb r0, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + + b .mppe_glis_ot +.pool + +vcmd_glissando_table: +.byte 0,1,4,8,16,32,64,96,128,255 + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_vibrato: @ VIBRATO (SPEED) +@--------------------------------------------------------------------------------------- + + @ vibrato... sets speed + cmp r2, #0 + beq .mppuv_vib_exit + sub r0, #203 + beq 1f + lsl r0, #2 + strb r0, [r7, #MCH_VIBSPD] +1: b mppe_DoVibrato +.mppuv_vib_exit: + bx lr + + + +/****************************************************************************** + * + * XM Volume Commands + * + ******************************************************************************/ + + + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------------- +.mppuv_xm: +@--------------------------------------------------------------------------------------- + +@ determine command type + + cmp r0, #0 @ 0 = none + beq .mppuv_exit4 + cmp r0, #0x50 + ble .mppuv_xm_setvol + cmp r0, #0x80 + blt .mppuv_xm_volslide + cmp r0, #0xA0 + blt .mppuv_xm_fvolslide + cmp r0, #0xC0 + blt .mppuv_xm_vibrato + cmp r0, #0xD0 + blt .mppuv_xm_panning + cmp r0, #0xF0 + blt .mppuv_xm_panslide + b .mppuv_xm_toneporta + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_setvol: @ Set Volume +@---------------------------------------------------------------------------------------- + + cmp R2, #0 + bne .mppuv_exit4 + sub r0, #0x10 + strb r0, [r7, #MCH_VOLUME] +.mppuv_exit4: + bx lr + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_volslide: @ Volume Slide +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + beq .mppuv_exit2 + ldrb r1, [r7, #MCH_VOLUME] + mov r3, #MCH_MEMORY+MPP_XM_VFX_MEM_VS + ldrb r2, [r7, r3] + cmp r0, #0x70 + bge .mppuv_xm_volslide_up + sub r0, #0x60 +.mppuv_xm_volslide_dn_check: + bne 1f + mov r0, r2 + lsl r0, #32-4 + lsr r0, #32-4 + b 2f +1: lsr r2, #4 + lsl r2, #4 + orr r2, r0 + strb r2, [r7, r3] +2: b .mppuv_voldownA + +.mppuv_xm_volslide_up: + sub r0, #0x70 +.mppuv_xm_volslide_up_check: + bne 1f + mov r0, r2 + lsr r0, #4 + b 2f +1: lsl r2, #32-4 + lsr r2, #32-4 + lsl r0, #4 + orr r2, r0 + lsr r0, #4 + strb r2, [r7, r3] +2: b .mppuv_volupA + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_fvolslide: @ Fine Volume Slide +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + bne .mppuv_exit4 + ldrb r1, [r7, #MCH_VOLUME] + mov r3, #MCH_MEMORY+MPP_XM_VFX_MEM_FVS + ldrb r2, [r7, r3] + cmp r0, #0x90 + bge .mppuv_xm_fvolslide_up + sub r0, #0x80 + b .mppuv_xm_volslide_dn_check +.mppuv_xm_fvolslide_up: + sub r0, #0x90 + b .mppuv_xm_volslide_up_check + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_vibrato: @ Vibrato +@---------------------------------------------------------------------------------------- + + @ xm vibrato + @ sets speed or depth + + cmp r2, #0 + beq .mppuv_xm_vibexit + cmp r0, #0xB0 + bge .mppuv_xm_vibdepth + +.mppuv_xm_vibspd: + sub r0, #0xA0 + lsl r0, #2 + beq 1f + strb r0, [r7, #MCH_VIBSPD] +1: b mppe_DoVibrato + +.mppuv_xm_vibdepth: + sub r0, #0xB0 + lsl r0, #3 + beq 1f + strb r0, [r7, #MCH_VIBDEP] +1: b mppe_DoVibrato + +.mppuv_xm_vibexit: + bx lr + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_panning: @ Panning +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + bne .mppuv_exit3 + sub r0, #0xC0 + lsl r0, #4 + cmp r0, #240 + beq .mppuv_xm_panhack + strb r0, [r7, #MCH_PANNING] + bx lr +.mppuv_xm_panhack: + mov r0, #255 + strb r0, [r7, #MCH_PANNING] +.mppuv_exit3: + bx lr + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_panslide: @ Panning Slide +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + beq .mppuv_exit3 + ldrb r2, [r7, #MCH_PANNING] + ldrb r3, [r7, #MCH_MEMORY + MPP_XM_VFX_MEM_PANSL] + cmp r0, #0xE0 + bge .mppuv_xm_panslide_right + sub r0, #0xD0 + bne 1f + lsr r0, r3, #4 + b 2f +1: lsl r3, #32-4 + lsr r3, #32-4 + lsl r0, #4 + orr r3, r0 + lsr r0, #4 + strb r3, [r7, #MCH_MEMORY + MPP_XM_VFX_MEM_PANSL] + +2: lsl r0, #2 + sub r2, r0 + bcs .mppuv_xm_panslide_set + mov r2, #0 + b .mppuv_xm_panslide_set +.mppuv_xm_panslide_right: + sub r0, #0xE0 + bne 1f + lsl r0, r3, #32-4 + lsr r0, #32-4 + b 2f +1: lsr r3, #4 + lsl r3, #4 + orr r3, r0 + strb r3, [r7, #MCH_MEMORY + MPP_XM_VFX_MEM_PANSL] +2: lsl r0, #2 + add r2, r0 + cmp r2, #255 + blt .mppuv_xm_panslide_set + mov r2, #255 +.mppuv_xm_panslide_set: + strb r2, [r7, #MCH_PANNING] + bx lr + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------- +.mppuv_xm_toneporta: @ Glissando +@------------------------------------------------------------------------------------- + + @ glissando... + @ on nonzero ticks, do a regular glissando slide at speed * 16 + cmp r2, #0 + beq 1f + + sub r0, #0xF0 + lsl r0, #4 + beq 2f + mov r1, #MCH_MEMORY+MPP_XM_VFX_MEM_GLIS + strb r0, [r7, r1] +2: ldrb r0, [r7, r1] + mov r1, r0 + + b .mppe_glis_backdoor + +1: bx lr + + + +/****************************************************************************** + * + * Module Effects + * + ******************************************************************************/ + + + +/****************************************************************************** + * mpp_ProcessEffect() + * + * Process pattern effect. + ******************************************************************************/ + .global mpp_Process_Effect + .thumb_func +mpp_Process_Effect: + + push {lr} + ldrb r0, [r7, #MCH_EFFECT] @ get effect# + ldrb r1, [r7, #MCH_PARAM] @ r1 = param + bl mpp_Channel_ExchangeMemory + + lsl r0, #1 + + pop {r2} + mov lr, r2 + + mov r2, r8 + ldrb r2, [r2, #MPL_TICK] @ r2 = tick# + + cmp r2, #0 @ Z flag = tick0 :) + add r0, pc + mov pc, r0 + + b mppe_todo + b mppe_SetSpeed + b mppe_PositionJump + b mppe_PatternBreak + b mppe_VolumeSlide + b mppe_Portamento + b mppe_Portamento + b mppe_Glissando + b mppe_Vibrato + b mppe_todo + b mppe_Arpeggio + b mppe_VibratoVolume + b mppe_PortaVolume + b mppe_ChannelVolume + b mppe_ChannelVolumeSlide + b mppe_SampleOffset + b mppe_todo + b mppe_Retrigger + b mppe_Tremolo @ tremolo + b mppe_Extended + b mppe_SetTempo + b mppe_FineVibrato + b mppe_SetGlobalVolume + b mppe_GlobalVolumeSlide + b mppe_SetPanning + b mppe_Panbrello + b mppe_ZXX + b mppe_SetVolume + b mppe_KeyOff + b mppe_EnvelopePos + b mppe_OldTremor +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_SetSpeed: @ EFFECT Axy: SET SPEED +@--------------------------------------------------------------------------------- + + bne .mppe_ss_exit @ dont set on nonzero ticks + cmp r1, #0 + beq .mppe_ss_exit + mov r0, r8 + + strb r1, [r0, #MPL_SPEED] +.mppe_ss_exit: +.thumb_func +mppe_todo: + bx lr @ exit + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PositionJump: @ EFFECT Bxy: SET POSITION +@--------------------------------------------------------------------------------- + + bne .mppe_pj_exit @ skip nonzero ticks + mov r0, r8 + strb r1, [r0, #MPL_PATTJUMP] +.mppe_pj_exit: + bx lr @ exit +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PatternBreak: @ EFFECT Cxy: PATTERN BREAK +@--------------------------------------------------------------------------------- + bne .mppe_pb_exit @ skip nonzero ticks + mov r0, r8 @ get variables + strb r1, [r0, #MPL_PATTJUMP_ROW] @ save param to row value + ldrb r1, [r0, #MPL_PATTJUMP] @ check if pattjump=empty + cmp r1, #255 @ 255=empty + bne .mppe_pb_exit @ ... + ldrb r1, [r0, #MPL_POSITION] @ if empty, set pattjump=position+1 + add r1, #1 + strb r1, [r0, #MPL_PATTJUMP] +.mppe_pb_exit: + bx lr @ finished +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------------ +mppe_VolumeSlide: @ EFFECT Dxy: VOLUME SLIDE +@------------------------------------------------------------------------------------------ + + push {lr} + ldrb r0, [r7, #MCH_VOLUME] @ load volume + + bl mpph_VolumeSlide64 + + strb r0, [r7, #MCH_VOLUME] @ save volume +.mppe_vs_zt: + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------- +mppe_Portamento: @ EFFECT Exy/Fxy: Portamento +@---------------------------------------------------------------------------------- + + push {lr} + +.mppe_pd_ot: + mov r3, #0 + mov r0, r1 + lsr r0, #4 @ test for Ex param (Extra fine slide) + cmp r0, #0xE @ .. +.mppe_pd_checkE: @ .. + bne .mppe_pd_checkF @ .. + cmp r2, #0 @ Extra fine slide: only slide on tick0 + bne .mppe_pd_exit @ .. + lsl r1, #32-4 @ mask out slide value + lsr r1, #32-4 @ .. + mov r3, #1 + b .mppe_pd_otherslide @ skip the *4 multiplication +.mppe_pd_checkF: @ ------------------------------------ + cmp r0, #0xF @ test for Fx param (Fine slide) + bne .mppe_pd_regslide @ .. + cmp r2, #0 @ Fine slide: only slide on tick0 + bne .mppe_pd_exit @ .. + lsl r1, #32-4 @ mask out slide value + lsr r1, #32-4 @ .. + b .mppe_pd_otherslide +.mppe_pd_regslide: + cmp r2, #0 + beq .mppe_pd_exit +.mppe_pd_otherslide: + + ldrb r0, [r7, #MCH_EFFECT] @ check slide direction + mov r2, #MCH_PERIOD + cmp r0, #5 @ .. (5 = portamento down) + ldr r0, [r7, r2] @ get period + + bne .mppe_pd_slideup @ branch to function +.mppe_pd_slidedown: @ -------SLIDE DOWN------- + + cmp r3, #0 + bne .mppe_pd_fineslidedown + bl mpph_PitchSlide_Down + + b .mppe_pd_store @ store & exit + +.mppe_pd_fineslidedown: + bl mpph_FinePitchSlide_Down + b .mppe_pd_store + +.mppe_pd_slideup: @ ---------SLIDE UP--------- + + cmp r3, #0 + bne .mppe_pd_fineslideup + bl mpph_PitchSlide_Up + b .mppe_pd_store +.mppe_pd_fineslideup: + bl mpph_FinePitchSlide_Up + +.mppe_pd_store: + mov r2, #MCH_PERIOD + ldr r1, [r7, #MCH_PERIOD] + str r0, [r7, #MCH_PERIOD] + sub r0, r1 + add r5, r0 +.mppe_pd_exit: + pop {r0} + bx r0 @ exit + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Glissando: @ EFFECT Gxy: Glissando +@--------------------------------------------------------------------------------- + + bne .mppe_glis_ot + + mov r0, r8 + ldrb r0, [r0, #MPL_FLAGS] + lsr r0, #C_FLAGS_GS + bcc 2f + @ gxx is shared, IT MODE ONLY!! + cmp r1, #0 + bne 3f + ldrb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + strb r1, [r7, #MCH_PARAM] +3: strb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + strb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] @ for simplification later + b .mppe_glis_ot + +2: @ gxx is separate + cmp r1, #0 + bne 3f + + ldrb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + strb r1, [r7, #MCH_PARAM] +3: strb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + + bx lr +// b .mppe_glis_exit +.mppe_glis_ot: + + push {lr} // save return address + + ldrb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + +.mppe_glis_backdoor: + + push {r1} + + cmp r6, #0 // exit if no active channel + bne 1f // + pop {r1,r3} // + bx r3 // +1: // + + ldrb r0, [r6, #MCA_SAMPLE] // get target period + sub r0, #1 // + mpp_SamplePointer // + ldrh r1, [r0, #C_MASS_FREQ] // + LSL R1, #2 // + ldrb r2, [r7, #MCH_NOTE] // + ldr r3,=mmGetPeriod // + bl mpp_call_r3 // + + pop {r1} // r1 = parameter + push {r0} // + + mov r3, r0 // r3 = target period + mov r2, #MCH_PERIOD // r0 = current period + ldr r0, [r7, r2] // + mov r2, r8 // test S flag + ldrb r2, [r2, #MPL_FLAGS] // + lsr r2, #C_FLAGS_SS // + bCC .mppe_glis_amiga + cmp r0, r3 + blt .mppe_glis_slideup + bgt .mppe_glis_slidedown +.mppe_glis_noslide: + pop {r0} + pop {r3} + bx r3 + +.mppe_glis_slideup: + bl mpph_PitchSlide_Up + pop {r1} + + cmp r0, r1 + blt .mppe_glis_store + mov r0, r1 + b .mppe_glis_store +.mppe_glis_slidedown: + bl mpph_PitchSlide_Down + pop {r1} + cmp r0, r1 + bgt .mppe_glis_store + mov r0, r1 +.mppe_glis_store: + + mov r2, #MCH_PERIOD + ldr r1, [r7, r2] @#MCA_PERIOD] + str r0, [r7, r2] @#MCA_PERIOD] + sub r0, r1 + add r5, r0 + +.mppe_glis_exit: + pop {r3} + bx r3 + + + //bx lr + +.mppe_glis_amiga: + + cmp r0, r3 + blt .mppe_glis_amiga_up + bgt .mppe_glis_amiga_down + pop {r0} + pop {r3} + bx r3 + +.mppe_glis_amiga_down: + bl mpph_PitchSlide_Up + pop {r1} + cmp r0, r1 + bgt .mppe_glis_store + mov r0, r1 + b .mppe_glis_store +.mppe_glis_amiga_up: + bl mpph_PitchSlide_Down + pop {r1} + cmp r0, r1 + blt .mppe_glis_store + mov r0, r1 + b .mppe_glis_store + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Vibrato: @ EFFECT Hxy: Vibrato +@--------------------------------------------------------------------------------- + + bne .mppe_v_ot + lsr r0, r1, #4 @ if (x != 0) { + beq .mppe_v_nospd @ speed = 4*x; + lsl r0, #2 @ .. + strb r0, [r7, #MCH_VIBSPD] @ .. +.mppe_v_nospd: + + lsl r0, r1, #32-4 @ if (y != 0) { + beq .mppe_v_nodep @ .. + lsr r0, #32-6 @ depth = y * 4; + mov r1, r8 + ldrb r1, [r1, #MPL_OLDEFFECTS] @ if(OldEffects) + lsl r0, r1 @ depth <<= 1; + strb r0, [r7, #MCH_VIBDEP] @ + b mppe_DoVibrato +.mppe_v_nodep: + BX LR + +.align 2 +.thumb_func +@------------------------------------------------------- +mppe_DoVibrato: +@------------------------------------------------------- + +.mppe_v_ot: + mov r0, r8 + ldrb r1, [r0, #MPL_TICK] + ldrb r0, [r0, #MPL_OLDEFFECTS] + + cmp r0, #0 + beq .mppe_dv_update + cmp r1, #0 + bne .mppe_dv_update + + push {lr} + ldrb r1, [r7, #MCH_VIBPOS] + b .mppe_dv_notupdate +.mppe_dv_update: + push {lr} + ldrb r0, [r7, #MCH_VIBSPD] + ldrb r1, [r7, #MCH_VIBPOS] + add r1, r0 + lsl r1, #32-8 + lsr r1, #32-8 + strb r1, [r7, #MCH_VIBPOS] +.mppe_dv_notupdate: + ldr r2,=mpp_TABLE_FineSineData + ldrsb r1, [r2, r1] + ldrb r0, [r7, #MCH_VIBDEP] + mul r1, r0 + asr r1, #8 + mov r0, r5 + cmp r1, #0 + blt .mppe_dv_negative + bl mpph_PitchSlide_Up + b .mppe_dv_store +.mppe_dv_negative: + neg r1, r1 + bl mpph_PitchSlide_Down +.mppe_dv_store: + mov r5, r0 + pop {r0} + bx r0 +// pop {pc} @ return THUMB +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Tremor: @ EFFECT Ixy: Tremor +@--------------------------------------------------------------------------------- + bx lr + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Arpeggio: @ EFFECT Jxy: Arpeggio +@--------------------------------------------------------------------------------- + + bne .mppe_arp_ot + + mov r0, #0 + strb r0, [r7, #MCH_FXMEM] +.mppe_arp_ot: + cmp r6, #0 + beq 1f + ldrb r0, [r7, #MCH_FXMEM] +// ldrb r3, [r6, #MCA_SAMPLE] ? ??? + cmp r0, #1 + bgt .mppe_arp_2 + beq .mppe_arp_1 +.mppe_arp_0: + mov r0, #1 + strb r0, [r7, #MCH_FXMEM] + @ do nothing! :) +1: bx lr + +.mppe_arp_1: + + mov r0, #2 @ set next tick to '2' + strb r0, [r7, #MCH_FXMEM] @ save... + mov r0, r5 + lsr r1, #4 @ mask out high nibble of param +.mppe_arp_others: + mov r2, r5 + cmp r1, #12 @ see if its >= 12 + blt .mppea1_12 @ .. + add r2, r5 @ add period if so... (octave higher) +.mppea1_12: @ .. + lsl r1, #4 @ *16*hword + + mov r0, r5 + push {lr} + bl mpph_LinearPitchSlide_Up + + mov r5, r0 + pop {r0} + bx r0 +// pop {pc} + +.mppe_arp_2: + mov r0, #0 + strb r0, [r7, #MCH_FXMEM] + mov r0, r5 + lsl r1, #32-4 + lsr r1, #32-4 + b .mppe_arp_others + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_VibratoVolume: @ EFFECT Kxy: Vibrato+Volume Slide +@--------------------------------------------------------------------------------- + + push {lr} + push {r1,r2} + bl mppe_DoVibrato + pop {r1,r2} + cmp r2, #0 + bl mppe_VolumeSlide + pop {r0} + bx r0 +// pop {pc} + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PortaVolume: @ EFFECT Lxy: Portamento+Volume Slide +@--------------------------------------------------------------------------------- + + push {lr} + push {r1,r2} + ldrb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + bl mppe_Glissando + pop {r1, r2} + cmp r2, #0 + bl mppe_VolumeSlide + pop {r0} + bx r0 +// pop {pc} + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_ChannelVolume: @ EFFECT Mxy: Set Channel Volume +@--------------------------------------------------------------------------------- + + bne .mppe_cv_exit @ quite simple... + cmp r1, #0x40 + bgt .mppe_cv_exit @ ignore command if parameter is > 0x40 + strb r1, [r7, #MCH_CVOLUME] +.mppe_cv_exit: + bx lr + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------ +mppe_ChannelVolumeSlide: @ EFFECT Nxy: Channel Volume Slide +@------------------------------------------------------------------------------------ + + push {lr} + + ldrb r0, [r7, #MCH_CVOLUME] @ load volume + bl mpph_VolumeSlide64 + + strb r0, [r7, #MCH_CVOLUME] @ save volume + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------- +mppe_SampleOffset: @ EFFECT Oxy Sample Offset +@---------------------------------------------------------------------------------- + + bne .mppe_so_exit @ skip on other ticks + + ldr r0,=mpp_vars + strb r1, [r0, #MPV_SAMPOFF] @ set offset +.mppe_so_exit: + bx lr +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PanningSlide: @ EFFECT Pxy Panning Slide +@--------------------------------------------------------------------------------- + + push {lr} + + mov r0, #255 + push {r0} + ldrb r0, [r7, #MCH_PANNING] @ load panning + + bl mpph_VolumeSlide + + strb r0, [r7, #MCH_PANNING] @ save panning + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Retrigger: @ EFFECT Qxy Retrigger Note +@--------------------------------------------------------------------------------- + + ldrb r0, [r7, #MCH_FXMEM] + cmp r0, #0 + bne .mppe_retrig_refillN +.mppe_retrig_refill: + lsl r0, r1, #32-4 + lsr r0, #32-4 + add r0, #1 +.mppe_retrig_exitcount: + strb r0, [r7, #MCH_FXMEM] + bx lr +.mppe_retrig_refillN: + sub r0, #1 + cmp r0, #1 + bne .mppe_retrig_exitcount +.mppe_retrig_fire: + + ldrb r2, [r7, #MCH_VOLUME] + lsr r0, r1, #4 + beq .mppe_retrig_v_change0 + cmp r0, #5 + ble .mppe_retrig_v_change_sub + cmp r0, #6 + beq .mppe_retrig_v_change_23 + cmp r0, #7 + beq .mppe_retrig_v_change_12 + cmp r0, #8 + beq .mppe_retrig_v_change0 + cmp r0, #0xD + ble .mppe_retrig_v_change_add + cmp r0, #0xE + beq .mppe_retrig_v_change_32 + cmp r0, #0xF + beq .mppe_retrig_v_change_21 +.mppe_retrig_v_change_21: + lsl r2, #1 + cmp r2, #64 + blt .mppe_retrig_finish + mov r2, #64 +.mppe_retrig_v_change0: + b .mppe_retrig_finish +.mppe_retrig_v_change_sub: + sub r0, #1 + mov r3, #1 + lsl r3, r0 + sub r2, r3 + bcs .mppe_retrig_finish + mov r2, #0 + b .mppe_retrig_finish +.mppe_retrig_v_change_23: + mov r0, #171 + mul r2, r0 + lsr r2, #8 + b .mppe_retrig_finish +.mppe_retrig_v_change_12: + lsr r2, #1 + b .mppe_retrig_finish +.mppe_retrig_v_change_add: + sub r0, #9 + mov r3, #1 + lsl r3, r0 + add r2, r3 + cmp r2, #64 + blt .mppe_retrig_finish + mov r2, #64 + b .mppe_retrig_finish +.mppe_retrig_v_change_32: + mov r0, #192 + mul r2, r0 + lsr r2, #7 +.mppe_retrig_finish: + strb r2, [r7, #MCH_VOLUME] + cmp r6, #0 + beq .mppe_retrig_refill + ldrb r0, [r6, #MCA_FLAGS] + mov r2, #MCAF_START + orr r0, r2 + strb r0, [r6, #MCA_FLAGS] + b .mppe_retrig_refill + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Tremolo: @ EFFECT Rxy: Tremolo +@--------------------------------------------------------------------------------- + +@ r1 = param +@ Z = tick0 + + beq .mppe_trem_zt @ skip this part on tick0 +.mppe_trem_ot: + @ X = speed, Y = depth + ldrb r0, [r7, #MCH_FXMEM] @ get sine position + lsr r3, r1, #4 @ mask out SPEED + lsl r3, #2 @ speed*4 to compensate for larger sine table + add r0, r3 @ add to position + strb r0, [r7, #MCH_FXMEM] @ save (value & 255) +.mppe_trem_zt: + ldrb r0, [r7, #MCH_FXMEM] @ get sine position + ldr r3,=mpp_TABLE_FineSineData @ load sine table value + ldrsb r0, [r3, r0] + lsl r1, #32-4 @ mask out DEPTH + lsr r1, #32-4 + mul r0, r1 @ SINE*DEPTH / 64 + asr r0, #6 + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_XS + bcs 1f + asr r0, #1 +1: ldr r1,=mpp_vars @ set volume addition variable + strb r0, [r1, #MPV_VOLPLUS] + bx lr +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Extended: @ EFFECT Sxy: Extended Effects +@--------------------------------------------------------------------------------- + + lsr r0, r1, #4 + lsl r0, #1 + cmp r2, #0 + add r0, pc + mov pc, r0 + + @ branch table... + b mppex_XM_FVolSlideUp @ S0x + b mppex_XM_FVolSlideDown @ S1x + b mppex_OldRetrig @ S2x + b mppex_VibForm @ S3x + b mppex_TremForm @ S4x + b mppex_PanbForm @ S5x + b mppex_FPattDelay @ S6x + b mppex_InstControl @ S7x + b mppex_SetPanning @ S8x + b mppex_SoundControl @ S9x + b mppex_HighOffset @ SAx + b mppex_PatternLoop @ SBx + b mppex_NoteCut @ SCx + b mppex_NoteDelay @ SDx + b mppex_PatternDelay @ SEy + b mppex_SongMessage @ SFx + +.mppe_ex_quit: + +@------------------------------------------- +.thumb_func +mppex_Unused: + bx lr + +@------------------------------------------- + +.thumb_func +mppex_XM_FVolSlideUp: + bne 2f + ldrb r0, [r7, #MCH_VOLUME] + lsl r1, #32-4 + lsr r1, #32-4 + add r0, r1 + cmp r0, #64 + blt 1f + mov r0, #64 +1: strb r0, [r7, #MCH_VOLUME] +2: bx lr + +.thumb_func +mppex_XM_FVolSlideDown: + bne 2f + ldrb r0, [r7, #MCH_VOLUME] + lsl r1, #32-4 + lsr r1, #32-4 + sub r0, r1 + bcs 1f + mov r0, #0 +1: strb r0, [r7, #MCH_VOLUME] +2: bx lr + +@------------------------------------------- +.thumb_func +mppex_OldRetrig: + bne 1f + lsl r1, #32-4 + lsr r1, #32-4 + strb r1, [r7, #MCH_FXMEM] + bx lr + +1: ldrb r0, [r7, #MCH_FXMEM] + sub r0, #1 + + bne 1f + + lsl r0, r1, #32-4 + lsr r0, #32-4 + strb r0, [r7, #MCH_FXMEM] + + cmp r6, #0 + beq 1f + ldrb r1, [r6, #MCA_FLAGS] + mov r2, #MCAF_START + + orr r1, r2 + strb r1, [r6, #MCA_FLAGS] + +1: strb r0, [r7, #MCH_FXMEM] + bx lr + +@------------------------------------------- +.thumb_func +mppex_VibForm: + bx lr + +@------------------------------------------- +.thumb_func +mppex_TremForm: + bx lr + +@------------------------------------------- +.thumb_func +mppex_PanbForm: + bx lr + +@------------------------------------------- +.thumb_func +mppex_FPattDelay: + bne .mppex_fpd_exit + lsl r1, #32-4 + lsr r1, #32-4 + mov r0, r8 + strb r1, [r0, #MPL_FPATTDELAY] +.mppex_fpd_exit: + bx lr + +@------------------------------------------- +.thumb_func +mppex_InstControl: + bne .mppex_ic_exit + lsl r1, #32-4 + lsr r1, #32-4 + cmp r1, #2 + ble .mppex_ic_pastnotes + cmp r1, #6 + ble .mppex_ic_nna + cmp r1, #8 + ble .mppex_ic_envelope + bx lr +.mppex_ic_pastnotes: + @ todo... + bx lr +.mppex_ic_nna: + @ overwrite NNA + sub r1, #3 + ldrb r2, [r7, #MCH_BFLAGS] + lsl r2, #32-6 + lsr r2, #32-6 + lsl r1, #6 + orr r2, r1 + strb r2, [r7, #MCH_BFLAGS] + bx lr +.mppex_ic_envelope: + cmp r6, #0 + beq .mppex_ic_exit + ldrb r2, [r6, #MCA_FLAGS] + mov r0, #32 + bic r2, r0 + sub r1, #7 + lsl r1, #5 + orr r2, r1 + strb r2, [r6, #MCA_FLAGS] + +.mppex_ic_exit: + bx lr + +@------------------------------------------- +.thumb_func +mppex_SetPanning: + lsl r1, #4 + strb r1, [r7, #MCH_PANNING] + bx lr + +@------------------------------------------- +.thumb_func +mppex_SoundControl: + cmp r1, #0x91 + beq .mppex_sc_surround + bx lr +.mppex_sc_surround: + @ set surround + bx lr + +@------------------------------------------- +.thumb_func +mppex_HighOffset: + @ todo... + bx lr + +@------------------------------------------- +.thumb_func +mppex_PatternLoop: + bne .mppex_pl_exit @ dont update on nonzero ticks + mov r2, r8 + + lsl r1, #32-4 @ mask low nibble of parameter + lsr r1, #32-4 @ ... + bne .mppex_pl_not0 @ is zero? + + ldrb r1, [r2, #MPL_ROW] @ ... + strb r1, [r2, #MPL_PLOOP_ROW] @ ... + ldr r1,=mpp_vars @ .... + ldr r1, [r1, #MPV_PATTREAD_P] @ .. ... + mov r3, #MPL_PLOOP_ADR + str r1, [r2, r3] @ ... ... + bx lr @ ... ... +.mppex_pl_not0: @ otherwise... + ldrb r0, [r2, #MPL_PLOOP_TIMES] @ get pattern loop counter + cmp r0, #0 @ zero? + bne .mppex_pl_active @ if not then its already active + strb r1, [r2, #MPL_PLOOP_TIMES] @ zero: save parameter to counter + b .mppex_pl_exit_enable @ exit & enable jump +.mppex_pl_active: @ nonzero: + sub r0, #1 @ decrement counter + strb r0, [r2, #MPL_PLOOP_TIMES] @ save + beq .mppex_pl_exit @ enable jump if not 0 +.mppex_pl_exit_enable: + mov r0, #1 @ enable jump + mov r3, #MPL_PLOOP_JUMP + strb r0, [r2, r3] @ .. +.mppex_pl_exit: @ exit + bx lr @ .... +.pool + +@------------------------------------------- +.thumb_func +mppex_NoteCut: + lsl r1, #32-4 @ mask parameter + lsr r1, #32-4 @ .. + cmp r1, r2 @ compare with tick# + bne .mppex_nc_exit @ if equal: + mov r0, #0 @ cut volume + strb r0, [r7, #MCH_VOLUME] @ .. +.mppex_nc_exit: @ exit + bx lr @ .. + +@------------------------------------------- +.thumb_func +mppex_NoteDelay: + + mov r0, r8 + ldrb r2, [r0, #MPL_TICK] + lsl r1, #32-4 + lsr r1, #32-4 + cmp r2, r1 + bge 1f + ldr r0,=mpp_vars + strb r1, [r0, #MPV_NOTEDELAY] +1: bx lr + +@------------------------------------------- +.thumb_func +mppex_PatternDelay: + bne .mppex_pd_quit @ update on tick0 + lsl r1, #32-4 @ mask parameter + lsr r1, #32-4 @ .. + mov r0, r8 + ldrb r2, [r0, #MPL_PATTDELAY] @ get patterndelay + cmp r2, #0 @ only update if it's 0 + bne .mppex_pd_quit @ .. + add r1, #1 @ set to param+1 + strb r1, [r0, #MPL_PATTDELAY] @ .. +.mppex_pd_quit: @ exit + bx lr @ .. + +@------------------------------------------- +.thumb_func +mppex_SongMessage: + + bne .mppex_pd_quit @ update on tick0 + push {lr} @ save return address + lsl r1, #32-4 @ mask parameter + lsr r1, #32-4 @ .. + ldr r2,=mmCallback + ldr r2, [r2] + cmp r2, #0 + beq 1f + mov r0, #MPCB_SONGMESSAGE + + bl mpp_call_r2 + @jump2 +1: //pop {pc} + pop {r0} + bx r0 +.pool + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +mppe_SetTempo: @ EFFECT Txy: Set Tempo / Tempo Slide +@---------------------------------------------------------------------------------------- + + @ 0x = slide down + @ 1x = slide up + @ 2x+ = set + + // BUGGED??? + // not using setbpm for slides??? + + cmp r1, #0x20 + bge .mppe_st_set + cmp r2, #0 + beq .mppe_st_exit + + mov r0, r8 + ldrb r2, [r0, #MPL_BPM] + + cmp r1, #0x10 + bge .mppe_st_slideup +.mppe_st_slidedown: + sub r2, r1 + cmp r2, #32 + bge .mppe_st_save + mov r2, #32 +.mppe_st_save: + mov r0, r2 + b .mppe_st_set2 +.mppe_st_slideup: + + lsl r1, #32-4 + lsr r1, #32-4 + + add r2, r1 + cmp r2, #255 + blt .mppe_st_save + mov r2, #255 + b .mppe_st_save +.mppe_st_set: + cmp r2, #0 + bne .mppe_st_exit + mov r0, r1 +.mppe_st_set2: + push {r5,lr} + mov r5, r8 + ldr r1,=mpp_setbpm + bl mpp_call_r1 + @jump1 + pop {r5} + pop {r3} + bx r3 +.mppe_st_exit: + bx lr +.pool + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +mppe_FineVibrato: @ EFFECT Uxy: Fine Vibrato +@---------------------------------------------------------------------------------------- + + bne .mppe_fv_ot + lsr r0, r1, #4 + beq .mppe_fv_nospd + lsl r0, #2 + strb r0, [r7, #MCH_VIBSPD] +.mppe_fv_nospd: + + lsl r0, r1, #32-4 + beq .mppe_fv_nodep +// lsr r0, #32 heh... + lsr r0, #32-4 + mov r1, r8 + ldrb r1, [r1, #MPL_OLDEFFECTS] + lsl r0, r1 + strb r0, [r7, #MCH_VIBDEP] +.mppe_fv_nodep: + +.mppe_fv_ot: + b mppe_DoVibrato +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------ +mppe_SetGlobalVolume: @ EFFECT Vxy: Set Global Volume +@------------------------------------------------------------------------------------ + + bne .mppe_sgv_exit @ on tick0: + mov r0, r8 + ldrb r2, [r0, #MPL_FLAGS] + mov r3, #(1<<(C_FLAGS_XS-1))+(1<<(C_FLAGS_LS-1)) + tst r2, r3 + beq 1f + mov r2, #0x40 + b 2f +1: mov r2, #0x80 +2: + cmp r1, r2 + blt 1f + mov r1, r2 +1: strb r1, [r0, #MPL_GV] @ save param to global volume +.mppe_sgv_exit: + bx lr +.pool + + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------- +mppe_GlobalVolumeSlide: @ EFFECT Wxy: Global Volume Slide +@---------------------------------------------------------------------------------- + + push {lr} + +.mppe_gvs_ot: + mov r0, r8 + ldrb r0, [r0, #MPL_FLAGS] + lsr r0, #C_FLAGS_XS + bcs 1f + + mov r0, #128 + b 2f + +1: mov r0, #64 + +2: push {r0} + mov r0, r8 + ldrb r0, [r0, #MPL_GV] @ load global volume + + bl mpph_VolumeSlide @ slide.. + + mov r1, r8 + strb r0, [r1, #MPL_GV] @ save global volume + pop {r0} + bx r0 +// pop {pc} @ exit +.pool + + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------------- +mppe_SetPanning: @ EFFECT Xxy: Set Panning +@--------------------------------------------------------------------------------------- + + bne .mppe_sp_exit @ on tick0: + strb r1, [r7, #MCH_PANNING] @ set panning=param +.mppe_sp_exit: + bx lr +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------------- +mppe_Panbrello: @ EFFECT Yxy: Panbrello +@--------------------------------------------------------------------------------------- + + @ todo + bx lr + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_ZXX: @ EFFECT Zxy: Set Filter +@--------------------------------------------------------------------------------- + +@ ZXX IS NOT SUPPORTED + bx lr @ exit +.pool + +@======================================================================================= +@ OLD EFFECTS +@======================================================================================= + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_SetVolume: @ EFFECT 0xx: Set Volume +@----------------------------------------------------------------------------------- + + bne .mppe_sv_exit @ on tick0: + strb r1, [r7, #MCH_VOLUME] @ set volume=param +.mppe_sv_exit: + bx lr + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_KeyOff: @ EFFECT 1xx: Key Off +@----------------------------------------------------------------------------------- + cmp r1, r2 @ if tick=param: + bne .mppe_ko_exit @ + cmp r6, #0 + beq .mppe_ko_exit + ldrb r0, [r6, #MCA_FLAGS] @ clear keyon from flags + mov r1, #MCAF_KEYON @ + bic r0, r1 @ + strb r0, [r6, #MCA_FLAGS] @ +.mppe_ko_exit: + bx lr @ finished +.pool + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_EnvelopePos: @ EFFECT 1xx: Envelope Position +@----------------------------------------------------------------------------------- + bne .mppe_ep_ot @ on tick0: + cmp r6, #0 + beq .mppe_ep_ot + + @ - NOT SUPPORTED ANYMORE - + +@ strh r1, [r6, #MCA_ENVP_VOL] @ set volume envelope position +@ strh r1, [r6, #MCA_ENVP_PAN] @ set panning envelope positin + @ pitch envelope wasn't invented yet +.mppe_ep_ot: + bx lr @ finished + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_OldTremor: @ EFFECT 3xy: Old Tremor +@----------------------------------------------------------------------------------- + + bne .mppe_ot_ot + bx lr +.mppe_ot_ot: + ldrb r0, [r7, #MCH_FXMEM] + cmp r0, #0 + bne .mppe_ot_old +.mppe_ot_new: + ldrb r0, [r7, #MCH_BFLAGS+1] + mov r3, #0b110 + eor r0, r3 + strb r0, [r7, #MCH_BFLAGS+1] + lsr r0, #3 + bcc .mppe_ot_low + lsr r1, #4 + add r1, #1 + strb r1, [r7, #MCH_FXMEM] + b .mppe_ot_apply +.mppe_ot_low: + lsl r1, #32-4 + lsr r1, #32-4 + add r1, #1 + strb r1, [r7, #MCH_FXMEM] + b .mppe_ot_apply + +.mppe_ot_old: + sub r0, #1 + strb r0, [r7, #MCH_FXMEM] + +.mppe_ot_apply: + ldrb r2, [r7, #MCH_BFLAGS+1] + + lsr r2, #3 + bcs .mppe_ot_cut + mov r1, #-64&255 + ldr r2,=mpp_vars + strb r1, [r2, #MPV_VOLPLUS] +.mppe_ot_cut: + bx lr + +@=============================================================================== +@ FUNCTIONS!! +@=============================================================================== + +.align 2 +.thumb_func +@-------------------------------------------------------------------------- +mpph_PitchSlide_Down: @ Linear/Amiga slide down +@-------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (/4) + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psd_amiga + b .mpph_psd + +.thumb_func +@-------------------------------------------------------------------------- +mpph_LinearPitchSlide_Down: @ Linear slide down +@-------------------------------------------------------------------------- + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psu +.mpph_psd: + ldr r2,=mpp_TABLE_LinearSlideDownTable +.mpph_psd_fine: + lsl r1, #1 + ldrh r1, [r2, r1] + lsr r0, #5 + mul r0, r1 + lsr r0, #16 -5 +.mpph_psd_clip: + cmp r0, #0 + bge .mpph_psd_clipdone + mov r0, #0 +.mpph_psd_clipdone: + bx lr +.mpph_psd_amiga: + lsl r1, #4 +.mpph_psd_amiga_fine: + add r0, r1 + lsr r1, r0, #16+5 + beq .mpph_psd_clipdone + mov r0, #1 + lsl r0, #16+5 + b .mpph_psd_clip + +.align 2 +.thumb_func +@-------------------------------------------------------------------------- +mpph_PitchSlide_Up: @ Linear/Amiga slide up +@-------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (/4) + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psu_amiga + b .mpph_psu +.thumb_func +mpph_LinearPitchSlide_Up: @ Linear slide up + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psd +.mpph_psu: + ldr r2,=mpp_TABLE_LinearSlideUpTable + mov r3, r0 + cmp r1, #192 + blt .mpph_psu_notdouble + add r3, r3 +.mpph_psu_notdouble: +.mpph_psu_fine: + lsl r1, #1 + ldrh r1, [r2, r1] + lsr r0, #5 + mul r0, r1 + lsr r0, #16-5 + add r0, r3 +.mpph_psu_clip: + mov r1, r0 + lsr r1, #16+5 + beq .mpph_psu_clipped + mov r0, #1 + lsl r0, #16+5 +.mpph_psu_clipped: + bx lr +.mpph_psu_amiga: + lsl r1, #4 +.mpph_psu_amiga_fine: + sub r0, r1 + bcs .mpph_psu_clipped + mov r0, #0 + bx lr + +.align 2 +.thumb_func +@--------------------------------------------------------------------------- +mpph_FinePitchSlide_Up: +@--------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (0-15) + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_fpsu_amiga + ldr r2,=mpp_TABLE_FineLinearSlideUpTable + mov r3, r0 + b .mpph_psu_fine +.mpph_fpsu_amiga: + lsl r1, #2 + b .mpph_psu_amiga_fine + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mpph_FinePitchSlide_Down: +@----------------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (0-15) + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_fpsd_amiga + ldr r2,=mpp_TABLE_FineLinearSlideDownTable + b .mpph_psd_fine +.mpph_fpsd_amiga: + lsl r1, #2 + b .mpph_psd_amiga_fine +.pool + +@----------------------------------------------------------------------------------- + +.text +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mpph_FastForward: +@----------------------------------------------------------------------------------- + + @ r1 = #rows to skip + cmp r1, #0 + bne .mpph_ff +.mpph_ff_exitf: + bx lr +.mpph_ff: + + mov r0, r8 + ldrb r2, [r0, #MPL_NROWS] + add r2, #1 + cmp r1, r2 + bge .mpph_ff_exitf + strb r1, [r0, #MPL_ROW] + push {r7,lr} + ldr r7,=mmReadPattern //mpp_ReadPattern +.mpph_ff_loop: + push {r1,r7} + bl mpp_call_r7 + pop {r1,r7} + sub r1, #1 + bne .mpph_ff_loop + + pop {r7} + pop {r0} + bx r0 +// pop {pc} +.pool + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ IWRAM CODE @ +@ @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.align 2 +.thumb_func +@----------------------------------------------------------------------------- +mpph_VolumeSlide64: +@----------------------------------------------------------------------------- + + mov r3, #64 + push {r3} + +.thumb_func +@----------------------------------------------------------------------------- +mpph_VolumeSlide: +@----------------------------------------------------------------------------- + + @ r0 = volume + @ r1 = paramter + @ r2 = tick# + @ stack:1 = max volume + + mov r3, r8 + ldrb r3, [r3, #MPL_FLAGS] + lsr r3, #C_FLAGS_XS + bcs .mpph_vs_XM + + cmp r1, #0x0F @ is value 15? + bne .mpph_vs_hack1 @ then only slide on tick0 + b .mpph_vs_fsub +.mpph_vs_hack1: + cmp r1, #0xF0 @ is value 15? + bne .mpph_vs_hack2 @ then only slide on tick0 + cmp r2, #0 @ .. + bne .mpph_vs_exit @ .. + b .mpph_vs_fadd +.mpph_vs_hack2: + + mov r3, r1 @ test for Dx0 + lsl r3, #32-4 @ .. + bne .mpph_vs_next1 @ .. +.mpph_vs_add: @ Dx0: (used for DxF too) + cmp r2, #0 + beq .mpph_vs_exit +.mpph_vs_fadd: + lsr r1, #4 @ fix value + add r0, r1 @ add to volume + pop {r1} + cmp r0, r1 @ clip values past 64 + blt .mpph_vs_exit2 @ .. + mov r0, r1 @ .. + b .mpph_vs_exit2 @ .. +.mpph_vs_next1: @--------------------- + mov r3, r1 @ test for D0x + lsr r3, #4 @ .. + bne .mpph_vs_next2 @ .. +.mpph_vs_sub: @ D0x: + cmp r2, #0 + beq .mpph_vs_exit +.mpph_vs_fsub: + lsl r1, #32-4 @ mask value + lsr r1, #32-4 @ .. + + sub r0, r1 @ subtract from volume + bcs .mpph_vs_exit @ clip values under 0 + mov r0, #0 @ .. + b .mpph_vs_exit @ .. +.mpph_vs_next2: @--------------------- + cmp r2, #0 @ fine slides now... only slide on tick0 + bne .mpph_vs_exit @ .. + + mov r3, r1 @ test for DxF + lsl r3, #32-4 @ .. + lsr r3, #32-4 + cmp r3, #0x0F @ .. + beq .mpph_vs_fadd @ branch + + mov r3, r1 @ test for DFx + lsr r3, #4 @ .. + cmp r3, #0x0F @ .. + beq .mpph_vs_fsub @ branch +.mpph_vs_exit: + + pop {r1} + +.mpph_vs_exit2: + bx lr @ exit if all fail + +.mpph_vs_XM: + cmp r2, #0 + beq .mpph_vs_exit + + lsr r3, r1, #4 + lsl r1, #32-4 + lsr r1, #32-4 + sub r3, r1 + add r0, r3 + pop {r1} + cmp r0, r1 + blt .mpph_vsxm_testlow + mov r0, r1 +.mpph_vsxm_testlow: + cmp r0, #0 + bgt .mpph_vs_exit2 + mov r0, #0 + bx lr +.pool + +@========================================================================================== +@ TABLES +@========================================================================================== + +.TEXT + +.align 2 +/****************************************************************************** + * ST3_FREQTABLE + * + * LUT for amiga periods. + ******************************************************************************/ + .global ST3_FREQTABLE +ST3_FREQTABLE: + +.hword 1712*8, 1616*8, 1524*8, 1440*8, 1356*8, 1280*8, 1208*8, 1140*8, 1076*8, 1016*8, 960*8, 907*8 @ MORE ACCURACY SCALARS + +@middle octave is 4. +@ +@ 133808 * ( period(NOTE) >> octave ) +@ note_st3period = -------------------------------------------- +@ middle_c_finetunevalue(INSTRUMENT) +@ + +.align 2 +@------------------------------------------------------------------------------------------- +mpp_TABLE_LinearSlideUpTable: @ value = 2^(val/192), 16.16 fixed +@------------------------------------------------------------------------------------------- + +.hword 0, 237, 475, 714, 953 @ 0->4 @ ADD 1.0 +.hword 1194, 1435, 1677, 1920, 2164 @ 5->9 +.hword 2409, 2655, 2902, 3149, 3397 @ 10->14 +.hword 3647, 3897, 4148, 4400, 4653 @ 15->19 +.hword 4907, 5157, 5417, 5674, 5932 @ 20->24 +.hword 6190, 6449, 6710, 6971, 7233 @ 25->29 +.hword 7496, 7761, 8026, 8292, 8559 @ 30->34 +.hword 8027, 9096, 9366, 9636, 9908 @ 35->39 +.hword 10181, 10455, 10730, 11006, 11283 @ 40->44 +.hword 11560, 11839, 12119, 12400, 12682 @ 45->49 +.hword 12965, 13249, 13533, 13819, 14106 @ 50->54 +.hword 14394, 14684, 14974, 15265, 15557 @ 55->59 +.hword 15850, 16145, 16440, 16737, 17034 @ 60->64 +.hword 17333, 17633, 17933, 18235, 18538 @ 65->69 +.hword 18842, 19147, 19454, 19761, 20070 @ 70->74 +.hword 20379, 20690, 21002, 21315, 21629 @ 75->79 +.hword 21944, 22260, 22578, 22897, 23216 @ 80->84 +.hword 23537, 23860, 24183, 24507, 24833 @ 85->89 +.hword 25160, 25488, 25817, 26148, 26479 @ 90->94 +.hword 26812, 27146, 27481, 27818, 28155 @ 95->99 +.hword 28494, 28834, 29175, 29518, 29862 @ 100->104 +.hword 30207, 30553, 30900, 31248, 31599 @ 105->109 +.hword 31951, 32303, 32657, 33012, 33369 @ 110->114 +.hword 33726, 34085, 34446, 34807, 35170 @ 115->119 +.hword 35534, 35900, 36267, 36635, 37004 @ 120->124 +.hword 37375, 37747, 38121, 38496, 38872 @ 125->129 +.hword 39250, 39629, 40009, 40391, 40774 @ 130->134 +.hword 41158, 41544, 41932, 42320, 42710 @ 135->139 +.hword 43102, 43495, 43889, 44285, 44682 @ 140->144 +.hword 45081, 45481, 45882, 46285, 46690 @ 145->149 +.hword 47095, 47503, 47917, 48322, 48734 @ 150->154 +.hword 49147, 49562, 49978, 50396, 50815 @ 155->159 +.hword 51236, 51658, 52082, 52507, 52934 @ 160->164 +.hword 53363, 53793, 54224, 54658, 55092 @ 165->169 +.hword 55529, 55966, 56406, 56847, 57289 @ 170->174 +.hword 57734, 58179, 58627, 59076, 59527 @ 175->179 +.hword 59979, 60433, 60889, 61346, 61805 @ 180->184 +.hword 62265, 62727, 63191, 63657, 64124 @ 185->189 +.hword 64593, 65064, 0, 474, 950 @ 190->194 @ ADD 2.0 w/ 192+ +.hword 1427, 1906, 2387, 2870, 3355 @ 195->199 +.hword 3841, 4327, 4818, 5310, 5803 @ 200->204 +.hword 6298, 6795, 7294, 7794, 8296 @ 205->209 +.hword 8800, 9306, 9814, 10323, 10835 @ 210->214 +.hword 11348, 11863, 12380, 12899, 13419 @ 215->219 +.hword 13942, 14467, 14993, 15521, 16051 @ 220->224 +.hword 16583, 17117, 17653, 18191, 18731 @ 225->229 +.hword 19273, 19817, 20362, 20910, 21460 @ 230->234 +.hword 22011, 22565, 23121, 23678, 24238 @ 235->239 +.hword 24800, 25363, 25929, 25497, 27067 @ 240->244 +.hword 27639, 28213, 28789, 29367, 29947 @ 245->249 +.hword 30530, 31114, 31701, 32289, 32880 @ 250->254 +.hword 33473, 34068 @ 255->256 + +.align 2 +@------------------------------------------------------------------------------------- +mpp_TABLE_LinearSlideDownTable: @ value = 2^(-val/192), 16.16 fixed +@------------------------------------------------------------------------------------- + +.hword 65535, 65300, 65065, 64830, 64596, 64364, 64132, 63901 @ 0->7 +.hword 63670, 63441, 63212, 62984, 62757, 62531, 62306, 62081 @ 8->15 +.hword 61858, 61635, 61413, 61191, 60971, 60751, 60532, 60314 @ 16->23 +.hword 60097, 59880, 59664, 59449, 59235, 59022, 58809, 58597 @ 24->31 +.hword 58386, 58176, 57966, 57757, 57549, 57341, 57135, 56929 @ 32->39 +.hword 56724, 56519, 56316, 56113, 55911, 55709, 55508, 55308 @ 40->47 +.hword 55109, 54910, 54713, 54515, 54319, 54123, 53928, 53734 @ 48->55 +.hword 53540, 53347, 53155, 52963, 52773, 52582, 52393, 52204 @ 56->63 +.hword 52016, 51829, 51642, 51456, 51270, 51085, 50901, 50718 @ 64->71 +.hword 50535, 50353, 50172, 49991, 49811, 49631, 49452, 49274 @ 72->79 +.hword 49097, 48920, 48743, 48568, 48393, 48128, 48044, 47871 @ 80->87 +.hword 47699, 47527, 47356, 47185, 47015, 46846, 46677, 46509 @ 88->95 +.hword 46341, 46174, 46008, 45842, 45677, 45512, 45348, 45185 @ 96->103 +.hword 45022, 44859, 44698, 44537, 44376, 44216, 44057, 43898 @104->111 +.hword 43740, 43582, 43425, 43269, 43113, 42958, 42803, 42649 @112->119 +.hword 42495, 42342, 42189, 42037, 41886, 41735, 41584, 41434 @120->127 +.hword 41285, 41136, 40988, 40840, 40639, 40566, 40400, 40253 @128->135 +.hword 40110, 39965, 39821, 39678, 39535, 39392, 39250, 39109 @136->143 +.hword 38968, 38828, 38688, 38548, 38409, 38271, 38133, 37996 @144->151 +.hword 37859, 37722, 37586, 37451, 37316, 37181, 37047, 36914 @152->159 +.hword 36781, 36648, 36516, 36385, 36254, 36123, 35993, 35863 @160->167 +.hword 35734, 35605, 35477, 35349, 35221, 35095, 34968, 34842 @168->175 +.hword 34716, 34591, 34467, 34343, 34219, 34095, 33973, 33850 @176->183 +.hword 33728, 33607, 33486, 33365, 33245, 33125, 33005, 32887 @184->191 +.hword 32768, 32650, 32532, 32415, 32298, 32182, 32066, 31950 @192->199 +.hword 31835, 31720, 31606, 31492, 31379, 31266, 31153, 31041 @200->207 +.hword 30929, 30817, 30706, 30596, 30485, 30376, 30226, 30157 @208->215 +.hword 30048, 29940, 29832, 29725, 29618, 29511, 29405, 29299 @216->223 +.hword 29193, 29088, 28983, 28879, 28774, 28671, 28567, 28464 @224->231 +.hword 28362, 28260, 28158, 28056, 27955, 27855, 27754, 27654 @232->239 +.hword 27554, 27455, 27356, 27258, 27159, 27062, 26964, 26867 @240->247 +.hword 26770, 26674, 26577, 26482, 26386, 26291, 26196, 26102 @248->255 +.hword 26008 @ 256 + +/****************************************************************************** + * IT_PitchTable + * + * LUT for linear periods. + ******************************************************************************/ + .global IT_PitchTable + .align 2 +IT_PitchTable: + +.hword 2048, 0, 2170, 0, 2299, 0, 2435, 0, 2580, 0, 2734, 0 @ C-0 +.hword 2896, 0, 3069, 0, 3251, 0, 3444, 0, 3649, 0, 3866, 0 @>B-0 + +.hword 4096, 0, 4340, 0, 4598, 0, 4871, 0, 5161, 0, 5468, 0 @ C-1 +.hword 5793, 0, 6137, 0, 6502, 0, 6889, 0, 7298, 0, 7732, 0 @>B-1 + +.hword 8192, 0, 8679, 0, 9195, 0, 9742, 0, 10321, 0, 10935, 0 @ octave 2 +.hword 11585, 0, 12274, 0, 13004, 0, 13777, 0, 14596, 0, 15464, 0 + +.hword 16384, 0, 17358, 0, 18390, 0, 19484, 0, 20643, 0, 21870, 0 @ octave 3 +.hword 23170, 0, 24548, 0, 26008, 0, 27554, 0, 29193, 0, 30929, 0 + +.hword 32768, 0, 34716, 0, 36781, 0, 38968, 0, 41285, 0, 43740, 0 @ octave 4 +.hword 46341, 0, 49097, 0, 52016, 0, 55109, 0, 58386, 0, 61858, 0 + +.hword 0, 1, 3897, 1, 8026, 1, 12400, 1, 17034, 1, 21944, 1 @ octave 5 +.hword 27146, 1, 32657, 1, 38496, 1, 44682, 1, 51236, 1, 58179, 1 + +.hword 0, 2, 7794, 2, 16051, 2, 24800, 2, 34068, 2, 43888, 2 @ octave 6 +.hword 54292, 2, 65314, 2, 11456, 3, 23828, 3, 36936, 3, 50823, 3 + +.hword 0, 4, 15588, 4, 32103, 4, 49600, 4, 2601, 5, 22240, 5 @ octave 7 +.hword 43048, 5, 65092, 5, 22912, 6, 47656, 6, 8336, 7, 36110, 7 + +.hword 0, 8, 31176, 8, 64205, 8, 33663, 9, 5201, 10, 44481, 10 @ octave 8 +.hword 20559, 11, 64648, 11, 45823, 12, 29776, 13, 16671, 14, 6684, 15 + +.hword 0, 16, 62352, 16, 62875, 17, 1790, 19, 10403, 20, 23425, 21 @ octave 9 +.hword 41118, 22, 63761, 23, 26111, 25, 59552, 26, 33342, 28, 13368, 30 + +.align 2 +@------------------------------------------------------------------------------------- +mpp_TABLE_FineLinearSlideUpTable: +@------------------------------------------------------------------------------------- + +.hword 0, 59, 118, 178, 237 @ 0->4 ADD 1x +.hword 296, 356, 415, 475, 535 @ 5->9 +.hword 594, 654, 714, 773, 833 @ 10->14 +.hword 893 @ 15 + +.align 2 +@------------------------------------------------------------------------------------- +mpp_TABLE_FineLinearSlideDownTable: +@------------------------------------------------------------------------------------- + +.hword 65535, 65477, 65418, 65359, 65300, 65241, 65182, 65359 @ 0->7 +.hword 65065, 65006, 64947, 64888, 64830, 64772, 64713, 64645 @ 8->15 + +@------------------------------------------------------------------------------------- +mpp_TABLE_FineSineData: +@------------------------------------------------------------------------------------- + +.byte 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23 +.byte 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44 +.byte 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59 +.byte 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64 +.byte 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60 +.byte 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46 +.byte 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26 +.byte 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2 +.byte 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23 +.byte -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44 +.byte -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59 +.byte -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64 +.byte -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60 +.byte -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46 +.byte -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26 +.byte -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2 + +.end diff --git a/libs/maxmod/mm_mas_arm.S b/libs/maxmod/mm_mas_arm.S new file mode 100644 index 0000000..13df41e --- /dev/null +++ b/libs/maxmod/mm_mas_arm.S @@ -0,0 +1,612 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> background then its important, dont use this channel + bgt .mppac_found // 1/3 if < background then its disabled, use this channel + + cmp r2, r4, lsl#23 // 1 compare volume with our record + bls .mppac_next_test // 1/3 goto next if not less + mov r3, r0 // 1 otherwise save this channel + movs r2, r4, lsl#23 // 1 and volume level +// beq .mppac_finished // 1/3 exit immediately if volume is zero + b .mppac_next_test // 3 loop + // 17 +.mppac_finished: + mov r0, r3 +// cmp r0, #255 //trap +// 5: bge 5b +.mppac_found: + pop {r4,r5,r6} + bx lr + +.global mmReadPattern +@**************************************************** +mmReadPattern: +@**************************************************** + push {r10-r12} + ldr r11, [r8, #MPL_SONGADR] + ldrb r12, [r11, #C_MAS_INSTN] // read instr count + ldrb r11, [r8, #MPL_FLAGS] // read flags + mov r10, #1 // for various things + + ldr r0,=mpp_channels + ldr r9, [r0] + ldr r7, [r8, #MPL_PATTREAD] + ldr r0,=mpp_vars + str r7, [r0, #MPV_PATTREAD_P] + + mov r1, #0 + +@---------------------------------------------------------------- +readpattern: +@---------------------------------------------------------------- + + mov r5, #0 // clear flags + ldrb r3, [r7], #1 // read pattern byte + movs r3, r3, lsl#32-7 // mask channel# + beq end_of_row // 0 = end of row + rsb r3, r10, r3, lsr#32-7 // get channel number + orr r1, r10, lsl r3 + mov r0, #MCH_SIZE + mla r6, r3, r0, r9 // get channel pointer + ldrcsb r2, [r7], #1 // read new maskvariable if bit was set + strcsb r2, [r6, #MCH_CFLAGS] // and save it + ldrccb r2, [r6, #MCH_CFLAGS] // otherwise read previous flags + + tst r2, #1 // test note bit + beq no_note + ldrb r0, [r7], #1 // read note value + cmp r0, #254 // test if < 254 + strltb r0, [r6, #MCH_PNOTE] // [most common result] + blt no_note + orreq r5, #MF_NOTECUT // 254 is note-cut + orrgt r5, #MF_NOTEOFF // 255 is note-off +no_note: + + tst r2, #2 // shift out instrument bit + beq no_instrument + ldrb r0, [r7], #1 // read instrument value + tst r5, #MF_NOTEOFF|MF_NOTECUT + bne no_instrument // skip if note-off or cut is set + cmp r0, r12 // check if value > max instruments + movgt r0, #0 // zero if so + ldrb r3, [r6, #MCH_INST] // test if instrument is the same + cmp r0, r3 + beq same_instrument + movs r3, r11, lsr#C_FLAGS_LS // shift out 'mod/s3m' flag + orrcs r5, #MF_START // set start flag if old + orr r5, #MF_NEWINSTR // set new instrument flag +same_instrument: + strb r0, [r6, #MCH_INST] +no_instrument: + + tst r10, r2, lsr#3 // test volume & effect bits + ldrcsb r0, [r7], #1 // copy vcmd + strcsb r0, [r6, #MCH_VOLCMD] +no_vcmd: + beq no_effect + ldrb r0, [r7], #1 // copy effect + ldrb r3, [r7], #1 // copy param + orr r0, r3, lsl#8 + strh r0, [r6, #MCH_EFFECT] // write effect+param +no_effect: + orr r5, r2, lsr#4 // orr in the new flags + strb r5, [r6, #MCH_FLAGS] // save flags + b readpattern // loop +end_of_row: + str r7, [r8, #MPL_PATTREAD] // save read position + str r1, [r8, #MPL_MCH_UPDATE] // save update bits + pop {r10-r12} + bx lr // return + +.macro get_channel branch + ldrb r0, [r7, #MCH_ALLOC] // get channel + cmp r0, #255 // + bge \branch // no channel! + ldr r6,=mm_achannels // + ldr r6, [r6] // + mov r1, #MCA_SIZE // + mla r6, r0, r1, r6 // +.endm + +.global mmUpdateChannel_T0, mmUpdateChannel_TN +@*************************************************************************** +mmUpdateChannel_T0: // for tick 0 +@*************************************************************************** + push {lr} + + ldrb r5, [r7, #MCH_FLAGS] // read channel flags + tst r5, #MF_START // test start flag + beq dont_start_channel // skip section if cleared + + tst r5, #MF_HASFX // test effect flag + beq no_channel_effect + ldrh r0, [r7, #MCH_EFFECT] // read effect + and r1, r0, #0xFF +// cmp r1, #19 // test for 'SDx' (note delay) +// lsreq r2, r0, #12 +// cmpeq r2, #0xD +// beq dont_start_channel // dont start channel if delayed + + // test for glissando + tst r5, #MF_NEWINSTR + bne start_channel // always start channel if it's a new instrument + cmp r1, #0x7 // test if effect is Gxx + beq glissando_affected + +no_channel_effect: + tst r5, #MF_NEWINSTR // copeee + bne start_channel // always start channel if it's a new instrument + + tst r5, #MF_HASVCMD // test for volume commmand + beq start_channel // none = start channel + ldrb r0, [r8, #MPL_FLAGS] // read mod flags + movs r0, r0, lsr#C_FLAGS_XS // test for XM mode + ldrb r0, [r7, #MCH_VOLCMD] // read volume command + bcs xm_vcmd // branch +it_vcmd: // using IT effects: + cmp r0, #193 // glissando is 193..202 + blt start_channel + cmp r0, #202 + bgt start_channel + b glissando_affected +xm_vcmd: // using XM effects: + cmp r0, #0xF0 // glissando is Fx + bge glissando_affected + b start_channel +no_channel_vcmd: + +glissando_affected: + + get_channel start_channel +/* ldrb r0, [r7, #MCH_ALLOC] // if channel is invalid + cmp r0, #255 // then skip this + bge start_channel + + ldr r6,=mm_achannels // get channel + ldr r6, [r6] // + mov r1, #MCA_SIZE // + mla r6, r0, r1, r6 // +*/ + bl mmChannelStartACHN // start achn + bic r5, #MF_START // clear start flag + strb r5, [r7, #MCH_FLAGS] + b dont_start_channel + +start_channel: // ok start channel... + + ldr r2,=mpp_Channel_NewNote + mov lr, pc + bx r2 + get_channel mmUpdateChannel_TN_ + +// cmp r6, #0 +// beq mmUpdateChannel_TN_ + + bl mmChannelStartACHN // start achn +//---------------------------------------------- + // r2 = note, calculate period + ldrb r0, [r6, #MCA_SAMPLE] + subs r0, #1 + bcc no_sample_to_make_period + + ldrb r1, [r8, #MPL_FLAGS] + lsrs r1, #C_FLAGS_SS + bcs linear_periods + + ldr r3, [r8, #MPL_SONGADR] // read song addr + ldr r1, [r8, #MPL_SAMPTABLE]// get sample table + ldr r0, [r1, r0, lsl#2] // get sample address + add r0, r3 // add module base + + ldrh r1, [r0, #C_MASS_FREQ] // read tuning freq + lsl r1, #2 // shift ... +// mov r0, r2 // move this. + bl get_amiga_period + b got_period +linear_periods: + LDR R1,=IT_PitchTable + LDR R0, [R1, R2, LSL#2] + //bl get_linear_period +got_period: +//-------------------------------- + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + str r0, [r7, #MCH_PERIOD] // save period + ldrb r0, [r6, #MCA_FLAGS] // set start flag + orr r0, #MCAF_START + strb r0, [r6, #MCA_FLAGS] +no_sample_to_make_period: +//---------------------------------------------------- + + b channel_started + +dont_start_channel: + + get_channel mmUpdateChannel_TN___ + +channel_started: + tst r5, #MF_DVOL + beq dvol_skip + ldrb r0, [r7, #MCH_INST] + subs r0, #1 + bcc dvol_no_instrument + + ldr r2, [r8, #MPL_SONGADR] // get instrument pointer + ldr r1, [r8, #MPL_INSTTABLE] + ldr r0, [r1, r0, lsl#2] + add r0, r2 + + ldr r1, [r0, #C_MASI_NNA] // read nna,envflags,pan + ldrb r2, [r7, #MCH_BFLAGS] // read bflags + bic r2, #0b11000000 // clear old nna + orr r2, r1, lsl#6 // set new nna + strb r2, [r7, #MCH_BFLAGS] + + ldrb r2, [r6, #MCA_FLAGS] // read achn flags + bic r2, #MCAF_VOLENV + tst r1, #ENVFLAG_A<<8 + orrne r2, #MCAF_VOLENV + strb r2, [r6, #MCA_FLAGS] + + movs r1, r1, lsl#8+1 // shift out panning MSB + movcs r1, r1, lsr#24 // if set, use new panning value + strcsb r1, [r7, #MCH_PANNING] +dvol_no_instrument: + + ldrb r0, [r6, #MCA_SAMPLE] // read sample# + subs r0, #1 + bcc dvol_no_sample // exit if invalid + + ldr r2, [r8, #MPL_SONGADR] // get sample address + ldr r1, [r8, #MPL_SAMPTABLE] + ldr r0, [r1, r0, lsl#2] + //add r0, r2 + + ldrh r1, [r0, r2] + //ldrh r1, [r0, #C_MASS_DV] // read dvol & pan + strb r1, [r7, #MCH_VOLUME] // copy volume + movs r1, r1, lsl#24-7 + mov r1, r1, lsr#24 + strcsb r1, [r7, #MCH_PANNING] +dvol_skip: +dvol_no_sample: + + tst r5, #MF_START|MF_DVOL + beq dont_reset_volume + + ldrb r0, [r8, #MPL_FLAGS] + tst r0, #C_FLAGS_X + beq 1f + tst r5, #MF_DVOL + beq dont_reset_volume // xm stuff +1: +reset_volume: + mov r0, #(1<<10) // [1] + mov r1, #0 // [1] + mov r2, #0 // [1] + add r12, r6, #MCA_FADE // [1] + stmia r12, {r0-r2} // [19] + // [23] + strh r1, [r6, #MCA_ENVN_VOL] + strb r1, [r6, #MCA_ENVN_PIC] + + // the last bit of code sets fade to (1<<10) + // and clears ENVC_VOL,ENVC_PAN,ENVC_PIC, + // AVIB_DEP, and AVIB_POS + // second bit clears ENVN vars + + strb r1, [r7, #MCH_FXMEM] // clear fx memory + + ldrb r1, [r6, #MCA_FLAGS] // set keyon + orr r1, #MCAF_KEYON // and clear envend+fade + bic r1, #MCAF_ENVEND | MCAF_FADE + strb r1, [r6, #MCA_FLAGS] + +dont_reset_volume: + + tst r5, #MF_NOTEOFF // test noteoff bit + beq skip_noteoff + + ldrb r1, [r6, #MCA_FLAGS] // read flags + bic r1, #MCAF_KEYON // clear key-on + ldrb r0, [r8, #MPL_FLAGS] // read mod flags + tst r0, #C_FLAGS_X // test xm mode + orrne r1, #MCAF_FADE // XM starts fade immediately on note-off + strb r1, [r6, #MCA_FLAGS] +skip_noteoff: + + tst r5, #MF_NOTECUT // test notecut bit + movne r0, #0 // clear volume + strneb r0, [r7, #MCH_VOLUME] // on note-cut + + bic r5, #MF_START // clear start flag + strb r5, [r7, #MCH_FLAGS] // save flags + b mmUpdateChannel_TN_ +@************************************************************ +mmUpdateChannel_TN: // for other ticks +@************************************************************ + push {lr} + +mmUpdateChannel_TN_: + ldrb r0, [r7, #MCH_ALLOC] // get channel + cmp r0, #255 // + bge mmUpdateChannel_TN___ // no channel! + ldr r6,=mm_achannels // + ldr r6, [r6] // + mov r1, #MCA_SIZE // + mla r6, r0, r1, r6 // + +mmUpdateChannel_TN___: + + movge r6, #0 + + ldr r5, [r7, #MCH_PERIOD] // r5 will be used to hold the period + ldr r1,=mpp_vars + mov r0, #0 + strb r0, [r1, #MPV_SAMPOFF] // clear variables + strb r0, [r1, #MPV_VOLPLUS] + strb r0, [r1, #MPV_PANPLUS] + strb r0, [r1, #MPV_NOTEDELAY] + +//--------------------------------------------- +// Update Volume Commands +//--------------------------------------------- + + ldrb r0, [r7, #MCH_FLAGS] + tst r0, #MF_HASVCMD + ldrne r1,=mpp_Process_VolumeCommand + movne lr, pc + bxne r1 + //blne mpp_Process_VolumeCommand + +//--------------------------------------------- +// Update Effects +//--------------------------------------------- + + ldrb r0, [r7, #MCH_FLAGS] + tst r0, #MF_HASFX + ldrne r1,=mpp_Process_Effect + movne lr, pc + bxne r1 + //blne mpp_Process_Effect + +//--------------------------------------------- + + cmp r6, #0 + beq no_achn + ldrh r0, [r7, #MCH_VOLUME] // read volume & cvolume + and r1, r0, #255 // mask volume + mov r0, r0, lsr#8 // mask cvolume + mul r0, r1, r0 // multiply together + mov r0, r0, lsr#5 // shift + strb r0, [r6, #MCA_VOLUME] // save in achn volume + + ldr r1,=mpp_vars // + ldrsb r2, [r1, #MPV_VOLPLUS] // read volume addition + adds r0, r2, lsl#3 // add to volume + movmi r0, #0 + cmp r0, #129 + movcs r0, #128 + strb r0, [r1, #MPV_AFVOL] // store in immediate vol + + ldrb r0, [r1, #MPV_NOTEDELAY]// read note delay + cmp r0, #0 // dont update if nonzero + beq channel_update_achn + + ldrb r0, [r6, #MCA_FLAGS] + orr r0, #MCAF_UPDATED + strb r0, [r6, #MCA_FLAGS] + b no_achn + +channel_update_achn: + + ldrb r0, [r7, #MCH_PANNING] // copy panning + strb r0, [r6, #MCA_PANNING] + ldr r0, [r7, #MCH_PERIOD] // copy period + str r0, [r6, #MCA_PERIOD] + mov r0, #0 + strh r0, [r1, #MPV_PANPLUS] // WHAT IS THIS??? "@ <---- RESERVED FOR LATER USE, CLEAR TO ZERO TEMPORARILY" + + ldrb r0, [r6, #MCA_FLAGS] + orr r0, #MCAF_UPDATED + strb r0, [r6, #MCA_FLAGS] + + push {r4} + ldrb r4, [r7, #MCH_ALLOC] + ldr r1,=mpp_Update_ACHN_notest + mov lr, pc + bx r1 + + pop {r4} +no_achn: + pop {lr} + bx lr + +@*********************************************************** +mmChannelStartACHN: // returns r2=note +@*********************************************************** + ldrb r2, [r7, #MCH_BFLAGS+1] // clear tremor/cutvol + bic r2, #0b110 + strb r2, [r7, #MCH_BFLAGS+1] + + cmp r6, #0 // achn==0? + beq 1f // then skip this part + + mov r0, #ACHN_FOREGROUND // set foreground type + strb r0, [r6, #MCA_TYPE] + + ldrb r0, [r6, #MCA_FLAGS] // read flags + bic r0, #0b11000000 // clear SUB, EFFECT + ldr r1,=mpp_clayer // get layer + ldrb r1, [r1] + orr r0, r1, lsl#6 // orr into flags + orr r0, r10, r0, lsl#8 // orr PARENT + strh r0, [r6, #MCA_PARENT] // store parent/flags + ldrb r0, [r7, #MCH_INST] // copy instrument + strb r0, [r6, #MCA_INST] +1: ldreqb r0, [r7, #MCH_INST] + subs r0, #1 + bcc invalid_instrument + + ldr r2, [r8, #MPL_SONGADR] // get instrument pointer + ldr r1, [r8, #MPL_INSTTABLE] + ldr r0, [r1, r0, lsl#2] + add r0, r2 + + ldrb r2, [r7, #MCH_PNOTE] // get pattern note + + ldrh r1, [r0, #C_MASI_MAP] // read notemap offset + tst r1, #0x8000 // test MSB + beq full_notemap // if set: notemap doesnt exist! + // use single entry + cmp r6, #0 // if channel is valid + strneb r1, [r6, #MCA_SAMPLE] // write sample value + strb r2, [r7, #MCH_NOTE] // write note value (without notemap, all entries == PNOTE) + bx lr // return + +full_notemap: + + add r0, r2, lsl#1 // add note offset + ldrh r2, [r0, r1] // read notemap entry [instr+note*2+notemap_offset] + strb r2, [r7, #MCH_NOTE] // write note value + cmp r6, #0 // if channel is valid + mov r0, r2, lsr#8 // write sample value + strneb r0, [r6, #MCA_SAMPLE] // .. + and r2, #255 +invalid_instrument: + bx lr // return + +/********** + + cmp r6, #0 // read notemap [sample] + ldrneb r2, [r0, #C_MASI_MAP+1] + strneb r2, [r6, #MCA_SAMPLE] + +//invalid_instrument: // BUG??? + ldrb r2, [r0, #C_MASI_MAP] // read notemap [note] + strb r2, [r7, #MCH_NOTE] +invalid_instrument: + + bx lr +**************/ + +.global mmGetPeriod +@*********************************************************** +mmGetPeriod: +@*********************************************************** + + ldrb r0, [r8, #MPL_FLAGS] + lsrs r0, #C_FLAGS_SS + bcs get_linear_period // tuning not used here with linear periods + +get_amiga_period: + adr r3, note_table_mod // get octave/mod from note + ldrb r0, [r3, r2] + sub r3, #3*10 + ldrb r2, [r3, r2, lsr#2] + + // r0 = (note mod 12) << 1 + // r1 = tuning + // r2 = (note / 12) + + ldr r3,=ST3_FREQTABLE // read st3 table entry + ldrh r0, [r3, r0] + + mov r3, #0x00AB0 // r3 = 133808 + orr r3, #0x20000 + mul r0, r3, r0 // multiply by magic number... + mov r0, r0, lsr r2 // shift by octave + cmp r1, #0 + beq 1f + swi SWI_DIVIDE<<16 // divide value / tuning +1: bx lr + +.global note_table_oct // remove this, make this static +.global note_table_mod // remove this, make this staic +note_table_oct: +.byte 0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5, 6,6,6 ,7,7,7,8,8,8,9,9,9 +note_table_mod: +.byte 0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0 +.align 2 + +get_linear_period: + ldr r1,=IT_PitchTable + ldr r0, [r1, r2, lsl#2] + bx lr + +.pool diff --git a/libs/maxmod/mm_mixer_gba.S b/libs/maxmod/mm_mixer_gba.S new file mode 100644 index 0000000..16bdeb7 --- /dev/null +++ b/libs/maxmod/mm_mixer_gba.S @@ -0,0 +1,1367 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> + +@ read frequency value + + ldr rfreq, [rchan, #CHN_FREQ] + cmp rfreq, #0 + beq .mpm_next @ EXIT if zero ----------------=-> + + ldr r0,=mm_ratescale + ldr r0, [r0] + mul rfreq, r0 + lsr rfreq, #14 + +@ load mixing buffers + + ldr rmixb,=mm_mixbuffer + ldr rmixb,[rmixb] + +@ get read position + + ldr rread, [rchan, #CHN_READ] + +@ calculate volume + + ldrb rvolR,[rchan, #CHN_VOL] @ volume = 0-255 + ldrb r0, [rchan, #CHN_PAN] @ pan = 0-255 + + rsb r0, r0, #256 + mul rvolL, r0, rvolR @ (vol*pan) = right volume + mov rvolL, rvolL, lsr#8 + add rvolA, rvolA, rvolL @ add to volume counter + rsb r0, r0, #256 + mul rvolR, r0, rvolR @ calc left volume (256-pan)*vol + mov rvolR, rvolR, lsr#8 + add rvolA, rvolA, rvolR, lsl#16 + + ldr rmixc, [sp] @ get mix count + +@**************************************************************** +.mpm_remix_test: +@**************************************************************** + + mov r2, #0 + mul r1, rmixc, rfreq // get number of samples that will be read + + cmp rfreq, #FETCH_THRESHOLD + bge 1f + + cmp r1, #FETCH_SIZE<<12 // check if its > fetch size + movhi r1, #FETCH_SIZE<<12 // if so: clamp to fetch size and set flag + movhi r2, #1 + +1: +// ldr r0, [rchan, #CHN_LEN] // now subtract length - read to get # samples remaining + ldr r0, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LEN] + rsb r0, rread, r0, lsl#SAMPFRAC +// sub r0, r0, rread // in the source + cmp r1, r0 // clamp mix count + movhi r1, r0 + bhi .calc_mix + cmp r2, #0 + beq .mpm_mix_full + +.calc_mix: + + + push {r1} // preserve sample count + + +//-------------------------------- +.macro DIV_ITER shift +//-------------------------------- + cmp r0, rfreq, lsl#\shift + subcs r0, rfreq, lsl#\shift + addcs r2, #1<<\shift +.endm +//-------------------------------- +.macro DIVIDER shift +//-------------------------------- + DIV_ITER \shift +.if \shift != 0 + DIVIDER (\shift-1) +.endif +.endm +//-------------------------------- + + mov r0, r1 // divide samples / frequency (24bit/16bit) + mov r2, #0 + +1: subs r0, rfreq, lsl#16 // divide top part + addcs r2, #1<<16 + bcs 1b + add r0, rfreq, lsl#16 + + DIVIDER 15 // divide the rest... + + cmp r0, #1 // round up result + adc r0, r2, #0 + +// mov r0,r1 +// mov r1,rfreq +// swi 0x060000 +// cmp r1, #0 +// addne r0, #1 + + pop {r1} // restore sample count + sub rmixc, r0 // subtract from mixcount + mov rmixcc, r0 + b .mpm_mix_short + +@------------------------------------------------------------------------ +@ SECTOR 2, MIXING +@------------------------------------------------------------------------ + +@----------------------------------------- +.mpm_mix_full: +@----------------------------------------- + +@ mix all samples + + mov rmixcc, rmixc @ <-- move mixing count + mov rmixc, #0 @ clear mixing count +.mpm_mix_short: + +@------------------------------------------------------ +.mpm_remix: +@------------------------------------------------------ + +@ mix samples... +@ preserve registers + stmfd sp!, {rmixc,rvolA,rchan} + +@ zero mixing count?? + cmp rmixcc, #0 + beq .mpm_mix_complete @ exit --------> + + cmp rfreq, #FETCH_THRESHOLD + bge .dont_use_fetch + + /* + ldr r0,=mm_fetch // transfer samples from ROM to RAM + add r1, #2<<14 // add threshold for safety + ldr r2,=REG_DMA3SAD + str r0, [r2, #4] + add r0, r10, rread, lsr#12 + bic r0, #0b11 + str r0, [r2, #0] + mov r0, #(1<<31)+(1<<26) + add r0, r1, lsr#14 + str r0, [r2, #8] + b fooo + */ + + // [cycle timings assume 3,1 ROM waitstates] + + push {r3-r12} + // r10 is SRC! + ldr r0,=mm_fetch // destination + add r10, r10, rread, lsr#12 // add read offset to source + bic r10, #0b11 // align to 32 bits + add r1, #4<<12 // add safety threshold + subs r1, #40<<12 // subtract 36 + + bcc .exit_fetch // skip large fetch if negative +.fetch: ldmia r10!, {r2-r9,r11,r14} // read 40 samples [44 cycles] + stmia r0!, {r2-r9,r11,r14} // write 40 samples [11 cycles] + subs r1, #40<<12 // count [1 cycle ] + bcc .exit_fetch // exit if done [1 cycle ] + ldmia r10!, {r2-r9,r11,r14} // read 40 samples [44 cycles] + stmia r0!, {r2-r9,r11,r14} // write 40 samples [11 cycles] + subs r1, #40<<12 // count [1 cycle ] + bcc .exit_fetch // exit if done [1 cycle ] + ldmia r10!, {r2-r9,r11,r14} // read 40 samples [44 cycles] + stmia r0!, {r2-r9,r11,r14} // write 40 samples [11 cycles] + subs r1, #40<<12 // count [1 cycle ] + bcs .fetch // loop if remaining [3 cycles] + // [173 cycles/120 samples] +.exit_fetch: + + adds r1, #(40<<12)-(24<<12) + bmi .end_medfetch +.medfetch: + ldmia r10!, {r2-r7} // read 24 samples [26] + stmia r0!, {r2-r7} // write 24 samples [7 ] + subs r1, #24<<12 // count [1 ] + bcc .end_medfetch // exit if done [1 ] + ldmia r10!, {r2-r7} // read 24 samples [26] + stmia r0!, {r2-r7} // write 24 samples [7 ] + subs r1, #24<<12 // count [1 ] + bcc .end_medfetch // exit if done [1 ] + ldmia r10!, {r2-r7} // read 24 samples [26] + stmia r0!, {r2-r7} // write 24 samples [7 ] + subs r1, #24<<12 // count [1 ] + bcs .medfetch // loop [3 ] +.end_medfetch: // [107] + + adds r1, #24<<12 // add 24 back + bmi .end_fetch // exit if <= 0 +.fetchsmall: + ldr r2, [r10], #4 // read 4 samples [8] + str r2, [r0], #4 // write 4 samples [2] + subs r1, #4<<12 // count [1] + ble .end_fetch // exit maybe [1] + ldr r2, [r10], #4 // read 4 samples [8] + str r2, [r0], #4 // write 4 samples [2] + subs r1, #4<<12 // count [1] + bgt .fetchsmall // exit maybe [3] +.end_fetch: + + pop {r3-r12} // restore regs + +fooo: + + mov r0, rread, lsr#12 // get read integer + push {r0, rsrc} // preserve regs + bic rread, r0, lsl#12 // clear integer + and r0, #0b11 // mask low bits + ldr rsrc,=mm_fetch // + add rsrc, rsrc, r0 // offset source (fetch is word aligned!) + +.dont_use_fetch: + + tst rmixb, #0b11 // test alignment of work output + beq .mpm_aligned + +#define rsamp1 r1 +#define rsampa r0 +#define rsampb r2 + @ routine to WORD align mixing sector + ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ load sample + add rread, rread, rfreq @ add frequency + mul rsampb, rsampa, rvolL @ multiply by left volume + ldrh rsamp1, [rmixb] @ add to mixing buffer (left) + add rsamp1, rsamp1, rsampb, lsr#5 + strh rsamp1, [rmixb], #4 + mul rsampb, rsampa, rvolR @ multiply by right volume + ldrh rsamp1, [rmixb] @ add to mixing buffer (right) + add rsamp1, rsamp1, rsampb, lsr#5 + strh rsamp1, [rmixb], #2 + sub rmixcc, rmixcc, #1 @ decrement mix count + +#undef rsamp1 +#undef rsampa +#undef rsampb + +.mpm_aligned: + // determine mixing mode + cmp rvolL, rvolR // if volume_left == volume_right then assume 'center' mixing + beq .mpm_mix_ac + cmp rvolL, #0 // if left volume is zero, do 'right' mixing + beq .mpm_mix_ar + cmp rvolR, #0 // if right volume is zero, do 'left' mixing + beq .mpm_mix_al + b mmMix_ArbPanning // otherwise do arb mixing +.mpm_mix_al: + b mmMix_HardLeft +.mpm_mix_ar: + b mmMix_HardRight + +@ center mixing------------ +.mpm_mix_ac: + cmp rvolL, #0 // check if volume is zero + bne mmMix_CenteredPanning // mix samples if not zero + b mmMix_Skip // skip samples if zero +.mpm_mix_complete: + + cmp rfreq, #FETCH_THRESHOLD + poplt {r0, rsrc} // restore regs + addlt rread, rread, r0, lsl#12 // add old integer to read + ldmfd sp!, {rmixc,rvolA,rchan} // restore more regs + + ldr r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LEN] + lsl r1, #SAMPFRAC + //ldr r1, [rchan, #CHN_LEN] // check length against position + cmp r1, rread + bgt .mpm_channelfinished + +// ldr r1, [rchan, #CHN_LOOP] // read channel loop + + ldr r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LOOP] + cmp r1, #0 +// movs r1, r1, lsl#8 // mask out high byte (that is VOLUME) + bmi .mpm_channel_stop // MSB = no loop, stop channel -> + + + sub rread,rread,r1,lsl#(SAMPFRAC) // subtract loop length (< + b .mpm_remix_test // yes: loop + +@---------------------------------------------------------------- +.mpm_channel_stop: +@---------------------------------------------------------------- + +@ *** END OF SAMPLE + mov r1, #1<<31 // disable channel + str r1, [rchan, #CHN_SRC] + +@ mix zero into the rest of the buffer + ldr rsrc,=mpm_nullsample // mix zero into the rest of the buffer + mov rfreq, #0 // zero freq + mov rread, #0 // zero freq + movs rmixcc, rmixc // mix remaining amount + ble .mpm_channelfinished // (exit if zero) + mov rmixc, #0 + mov r1, #0 + b .mpm_remix // mix 'zero' into the rest of the data + +@--------------------------------------------------------------- +.mpm_channelfinished: +@--------------------------------------------------------------- + + cmp rmixc, #0 // mix more samples? + bne .mpm_remix_test // yes: loop + +@ *** END OF MIXING *** + + str rread, [rchan, #CHN_READ] // save read position + +@----------------------- +.mpm_next: +@----------------------- + + add rchan, rchan, #CHN_SIZE // seek to next channel + ldr r0,=mm_mixch_end // compare with ending + ldr r0,[r0] + cmp rchan, r0 + bne .mpm_cloop // loop if != + +@---------------------------------------------------------------------------------- +@ SECTOR 3, POST-PROCESSING +@---------------------------------------------------------------------------------- + +#define prmixl r0 +#define prwritel r2 +#define prwriter r3 +#define prcount r4 +#define prvolR r12 +#define prvolL r11 +#define prsamp1 r6 +#define prsamp2 r5 +#define prsamp3 r7 + + ldr prmixl,=mm_mixbuffer + ldr prmixl,[prmixl] + + ldr prwritel,=mp_writepos + ldr prwritel, [prwritel] + ldr prwriter,=mm_mixlen + ldr prwriter, [prwriter] + add prwriter, prwritel, prwriter, lsl#1 @#MP_MIXLEN*2 + ldmfd sp!, {prcount} + +@ get volume accumulators + + mov prvolR, rvolA, lsr#16+1 + mov prvolR, prvolR, lsl#3 + + mov prvolL, rvolA, lsl#16 + mov prvolL, prvolL, lsr#16+1 + mov prvolL, prvolL, lsl#3 + + subs prcount, prcount, #1 + ble .mpm_copy2_end + +@-------------------------------------------------- +.mpm_copy2: +@-------------------------------------------------- + +@ ***************** LEFT OUTPUT ****************** + + ldr prsamp1, [prmixl], #4 @ get 2 mixed samples + sub prsamp2, prsamp1, prvolL @ convert to signed + + mov prsamp2, prsamp2, lsl#16 @ mask low hword with sign extension + movs prsamp2, prsamp2, asr#16+3 @ and convert 11-bit to 8-bit + + cmp prsamp2, #-128 @ clamp + movlt prsamp2, #-128 @ + cmp prsamp2, #127 @ + movgt prsamp2, #127 @ + + @ next sample... + rsbs prsamp3, prvolL, prsamp1,lsr#16 @ convert to signed + movs prsamp3, prsamp3, asr#3 @ convert 11-bit to 8-bit + + cmp prsamp3, #-128 @ clamp + movlt prsamp3, #-128 @ + cmp prsamp3, #127 @ + movgt prsamp3, #127 @ + + and prsamp2, prsamp2, #255 @ write to output + orr prsamp2, prsamp3, lsl#8 @ + strh prsamp2, [prwritel], #2 @ + +@ **************** RIGHT OUTPUT ****************** + + ldr prsamp1, [prmixl], #4 @ get 2 mixed samples + sub prsamp2, prsamp1, prvolR @ convert to signed + + mov prsamp2, prsamp2, lsl#16 @ mask low hword and convert 11-bit to 8-bit + movs prsamp2, prsamp2, asr#16+3 @ + + cmp prsamp2, #-128 @ clamp value + movlt prsamp2, #-128 @ + cmp prsamp2, #127 @ + movgt prsamp2, #127 @ + + @ next sample... + rsbs prsamp3, prvolR, prsamp1,lsr#16 @ convert to signed + movs prsamp3, prsamp3, asr#3 @ convert 11-bit to 8-bit + + cmp prsamp3, #-128 @ clamp value + movlt prsamp3, #-128 @ + cmp prsamp3, #127 @ + movgt prsamp3, #127 @ + + and prsamp2, prsamp2, #255 @ write to output + orr prsamp2, prsamp3, lsl#8 @ + strh prsamp2, [prwriter], #2 @ + + subs prcount, prcount, #2 @ loop + bgt .mpm_copy2 @ + +@------------------------------------------------------------------ + +.mpm_copy2_end: + ldr r0,=mp_writepos @ store new write position + str prwritel, [r0] + +@------------------------------------------------------------------ + + ldmfd sp!, {r4-r11,lr} // restore registers + bx lr // phew! + +.pool + +@================================================================================ +@ MIXING ROUTINES +@================================================================================ + +.macro READ_AND_INCREMENT reg + ldrb \reg, [rsrc, rread, lsr#SAMPFRAC] + add rread, rread, rfreq +.endm + +.macro READ_D reg, tmp + READ_AND_INCREMENT \reg + READ_AND_INCREMENT \tmp + orr \reg, \tmp, lsl#16 +.endm + +.macro MIX_D vol, tmp1, tmp2 + READ_D \tmp1, \tmp2 // load&combine 2 samples + mul \tmp2, \tmp1, \vol // multiply by volume + bic \tmp2, \tmp2, #0x1F0000 // prepare for shift +.endm + +.macro MIX_DA vol, target, tmp1, tmp2 + MIX_D \vol, \tmp1, \tmp2 + add \target, \target, \tmp2, lsr#5 // add 11-bit values +.endm + +.macro MIX_DC vol, target_a, target_b, tmp1, tmp2 + MIX_D \vol, \tmp1, \tmp2 + add \target_a, \target_a, \tmp2, lsr#5 // add 11-bit values + add \target_b, \target_b, \tmp2, lsr#5 +.endm + +.macro MIX_DB vol_l, vol_r, target_a, target_b, tmp1, tmp2 + READ_D \tmp1, \tmp2 + +.if \target_a != 0 + mul \tmp2, \tmp1, \vol_l // multiply by volume + bic \tmp2, \tmp2, #0x1F0000 // prepare for shift + add \target_a, \target_a, \tmp2, lsr#5 // add 11-bit values +.endif +.if \target_b != 0 + mul \tmp2, \tmp1, \vol_r // multiply by volume + bic \tmp2, \tmp2, #0x1F0000 // prepare for shift + add \target_b, \target_b, \tmp2, lsr#5 // add 11-bit values +.endif +.endm + +@----------------------------------------------------------------------------------- +mmMix_Skip: +@----------------------------------------------------------------------------------- + +@ mix nothing + mul r0, rmixcc, rfreq @ read += samples * frequency + add rread, rread, r0 + b .mpm_mix_complete + +@----------------------------------------------------------------------------------- +mmMix_HardLeft: +@----------------------------------------------------------------------------------- +@ mix hard panned left + + bl mmMix_SingleChannel // mix left channel + bgt mmMix_Remainder // mix remaining amount + b .mpm_mix_complete // return + +@----------------------------------------------------------------------------------- +mmMix_HardRight: +@----------------------------------------------------------------------------------- +@ hard panned right + + mov rvolL, rvolR // move volume + add rmixb, rmixb, #4 // offset to 'right' data + bl mmMix_SingleChannel // mix routine + mov rvolL, #0 // clear left volume again + sub rmixb, rmixb, #4 // remove offet + bgt mmMix_Remainder // mix remaining count + b .mpm_mix_complete // return + +@---------------------------------------- +mmMix_SingleChannel: +@---------------------------------------- + +#define rsamp1 r1 +#define rsamp2 r2 +#define rsamp3 r11 +#define rsamp4 r12 +#define rsampa r0 +#define rsampb r4 + +@ hard panned mixing (single channel mono) +@ interleaving really cuts this method's effectiveness :( + +@ mix 8 samples/loop + + subs rmixcc, rmixcc, #8 + bmi .mpmah_8e +.mpmah_8: + ldmia rmixb, {rsamp1, rsamp2, rsamp3} // load data [2nd word not used] + MIX_DA rvolL, rsamp1, rsampa, rsampb // mix data + str rsamp1, [rmixb], #8 // store mixed word + MIX_DA rvolL, rsamp3, rsampa, rsampb // mix data + str rsamp3, [rmixb], #8 // store mixed word + ldmia rmixb, {rsamp1, rsamp2, rsamp3} // load data [2nd word not used] + MIX_DA rvolL, rsamp1, rsampa, rsampb // mix data + str rsamp1, [rmixb], #8 // store mixed word + MIX_DA rvolL, rsamp3, rsampa, rsampb // mix data + str rsamp3, [rmixb], #8 // store mixed word + subs rmixcc, rmixcc, #8 // decrement 8 samples + bpl .mpmah_8 // loop if >= 0 +.mpmah_8e: + +@ mix remainder samples + + adds rmixcc, rmixcc, #8 // fix mixing count + bx lr // return + +#undef rsamp1 +#undef rsamp2 +#undef rsamp3 +#undef rsamp4 +#undef rsampa +#undef rsampb + +@---------------------------------------------------------- +mmMix_CenteredPanning: +@---------------------------------------------------------- + +#define rsamp1 r1 +#define rsamp2 r2 +#define rsamp3 r4 +#define rsamp4 r6 +#define rsamp5 r11 +#define rsamp6 r12 +#define rsampa r0 +#define rsampb lr + +@ mix center panning (double channel mono) + + subs rmixcc, rmixcc, #6 + bmi .mpmac_6e +.mpmac_6: + + ldmia rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5,rsamp6} // read words + MIX_DC rvolL, rsamp1, rsamp2, rsampa, rsampb // mix data + MIX_DC rvolL, rsamp3, rsamp4, rsampa, rsampb + MIX_DC rvolL, rsamp5, rsamp6, rsampa, rsampb + stmia rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5,rsamp6} // write words + subs rmixcc, rmixcc, #6 // count + bpl .mpmac_6 // loop +.mpmac_6e: + + mov rvolR, rvolL // restore right volume (same as left) + adds rmixcc, rmixcc, #6 // fix mix count + bgt mmMix_Remainder // mix remaining amount + b .mpm_mix_complete // finished mixing segment + +#undef rsamp1 +#undef rsamp2 +#undef rsamp3 +#undef rsamp4 +#undef rsamp5 +#undef rsamp6 +#undef rsampa +#undef rsampb + +@--------------------------------------------------- +mmMix_ArbPanning: // SLOWEST! +@--------------------------------------------------- + +#define rsamp1 r1 +#define rsamp2 r2 +#define rsamp3 r4 +#define rsamp4 r11 +#define rsampa r0 +#define rsampb r12 +#define rsamp5 r14 + + subs r3, r3, #10 + bmi .mpmaa_10e +.mpmaa_10: + + ldmia rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // load bufferdata + MIX_DB rvolL, rvolR, rsamp1, rsamp2, rsampa, rsampb // mix + MIX_DB rvolL, rvolR, rsamp3, rsamp4, rsampa, rsampb // mix + MIX_DB rvolL, rvolR, rsamp5, 0, rsampa, rsampb // mix half + stmia rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // store bufferdata + ldmia rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // load bufferdata + mul rsampb, rsampa, rvolR // mix other half + bic rsampb, rsampb, #0x1F0000 // .. + add rsamp1, rsamp1, rsampb, lsr#5 // .. + MIX_DB rvolL, rvolR, rsamp2, rsamp3, rsampa, rsampb // mix + MIX_DB rvolL, rvolR, rsamp4, rsamp5, rsampa, rsampb // mix + stmia rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // store bufferdata + subs rmixcc, rmixcc, #10 // count + bpl .mpmaa_10 // loop +.mpmaa_10e: + + adds rmixcc, rmixcc, #10 + bgt mmMix_Remainder + b .mpm_mix_complete + +.pool + +#undef rsamp1 +#undef rsamp2 +#undef rsamp3 +#undef rsamp4 +#undef rsampa +#undef rsampb + +//--------------------------------------------------------------------------- +mmMix_Remainder: +//--------------------------------------------------------------------------- +// (slow function to mix remaining amount of samples) +// assumes mix count isn't zero! + +#define rsamp1 r1 +#define rsamp2 r2 +#define rvol r11 +#define rsampa r0 +#define rsampb r4 + + orr rvol, rvolL, rvolR, lsl#16 + +.mix_remaining: +/* ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ 3 load sample + add rread, rread, rfreq @ 1 add frequency + mul rsampb, rsampa, rvolL @ 2 multiply by volume + ldrh rsamp1, [rmixb] @ 3 load mix buffer entry + add rsamp1, rsamp1, rsampb, lsr#5 @ 1 add + strh rsamp1, [rmixb], #2 @ 2 store + ldrh rsamp1, [rmixb, #2] @ 3 + mul rsampb, rsampa, rvolR @ 2 + add rsamp1, rsamp1, rsampb, lsr#5 @ 1 + strh rsamp1, [rmixb, #2] @ 2 +*/ + + ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ 3 load sample + add rread, rread, rfreq @ 1 add frequency + mul rsampb, rvol, rsampa @ 2 multiply by volume + ldrh rsamp1, [rmixb] @ 3 load mix buffer entry (left) + bic rsamp2, rsampb, #0xFF0000 @ 1 prep for shift + add rsamp1, rsamp1, rsamp2, lsr#5 @ 1 add + strh rsamp1, [rmixb], #2 @ 2 store (left) + ldrh rsamp1, [rmixb, #2] @ 3 load (right) + add rsamp1, rsamp1, rsampb, lsr#16+5 @ 1 add values + strh rsamp1, [rmixb, #2] @ 2 store (right) + + subs rmixcc, rmixcc, #2 @ 2 + blt .end_mix_remaining @ 1/exit + +/* ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ load sample + add rread, rread, rfreq @ add frequency + mul rsampb, rsampa, rvolL @ multiply by volume + ldrh rsamp1, [rmixb] @ load mix buffer entry + add rsamp1, rsamp1, rsampb, lsr#5 @ add + strh rsamp1, [rmixb], #4 @ store + ldrh rsamp1, [rmixb] + mul rsampb, rsampa, rvolR + add rsamp1, rsamp1, rsampb, lsr#5 + strh rsamp1, [rmixb], #2 +*/ + + ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ 3 load sample + add rread, rread, rfreq @ 1 add frequency + mul rsampb, rvol, rsampa @ 2 multiply by volume + ldrh rsamp1, [rmixb] @ 3 load mix buffer entry (left) + bic rsamp2, rsampb, #0xFF0000 @ 1 prep for shift + add rsamp1, rsamp1, rsamp2, lsr#5 @ 1 add + strh rsamp1, [rmixb], #4 @ 2 store (left) + ldrh rsamp1, [rmixb] @ 3 load (right) + add rsamp1, rsamp1, rsampb, lsr#16+5 @ 1 add values + strh rsamp1, [rmixb], #2 @ 2 store (right) + + bgt .mix_remaining +.end_mix_remaining: + + b .mpm_mix_complete + +#undef rsamp1 +#undef rsamp2 +#undef rvol +#undef rsampa +#undef rsampb + +@============================================================================ +@ END OF MIXER +@============================================================================ + + .TEXT + .THUMB + .ALIGN 2 + +/**************************************************************************** + * mmMixerSetSource( channel, p_sample ) + * + * Set channel source + ****************************************************************************/ + .thumb_func +mmMixerSetSource: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2, [r2] // + add r0, r2 // + + add r1, #C_SAMPLE_DATA // set sample data address + str r1, [r0, #CHN_SRC] // + + mov r1, #0 // reset read position + str r1, [r0, #CHN_READ] // + + bx lr + +/**************************************************************************** + * mmMixerSetRead( channel, value ) + * + * Set channel read position + ****************************************************************************/ + .thumb_func +mmMixerSetRead: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r2 // + + str r1, [r0, #CHN_READ] // store new offset + bx lr // + +/**************************************************************************** + * mmMixerSetFreq + * + * Set channel mixing rate + ****************************************************************************/ + .thumb_func +mmMixerSetFreq: + +// push {r3, r4} // FIXME: why would you preserve r3? + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2, r0 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r0, r2 // + + lsl r1, #2 // ... + + strh r1, [r0, #CHN_FREQ] + bx lr + +/* + ldr r4,=mm_freqscalar // r4=scale + ldr r4,[r4] // + + add r2, pc, #0 // switch to arm for a nice long multiply + bx r2 + + .ARM + + //------------------------------------ + // fix frequency to match mixing rate + // a = specified frequency + // hz = a*2y13 / pr + //------------------------------------ + + umull r3, r2, r1, r4 // long multiply + add r3, r3, #32768 // shift, etc.. + mov r3, r3, lsr#16 // + orr r3, r3, r2, lsl#16 // + + str r3, [r0, #CHN_FREQ] // set chan frequency + + ldmfd sp!, {r3,r4} // pop registers + bx lr // return + */ + .THUMB + +/**************************************************************************** + * mmMixerMulFreq( channel, value ) + * + * Scale mixing frequency + ****************************************************************************/ + .thumb_func +mmMixerMulFreq: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2, [r2] // + add r0, r2 // + + ldr r3, [r0, #CHN_FREQ] // scale + mul r3, r1 // + lsr r3, #10 // + str r3, [r0, #CHN_FREQ] // + bx lr + +/**************************************************************************** + * mmMixerStopChannel( channel ) + * + * Stop mixing channel + ****************************************************************************/ + .thumb_func +mmMixerStopChannel: + + mov r1, #CHN_SIZE // get channel pointer from index + mul r0, r1 // + ldr r1,=mm_mixchannels // + ldr r1,[r1] // + add r0, r1 // + + mov r1, #1 // set MSB (disable) of source + lsl r1, #31 // + str r1, [r0] // + bx lr + +/**************************************************************************** + * mmMixerChannelActive( channel ) + * + * Test if mixing channel is active + ****************************************************************************/ + .thumb_func +mmMixerChannelActive: + + mov r1, #CHN_SIZE // get channel pointer from index + mul r0, r1 // + ldr r1,=mm_mixchannels // + ldr r1,[r1] // + add r0, r1 // + +mp_Mixer_ChannelEnabledA: + ldr r0, [r0, #CHN_SRC] // nonzero (-1) = enabled + asr r0, #31 // zero = disabled + mvn r0, r0 // + bx lr + +/**************************************************************************** + * mmMixerSetVolume( channel, volume ) + * + * Set channel volume + ****************************************************************************/ + .thumb_func +mmMixerSetVolume: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r2 // + + strb r1, [r0, #CHN_VOL] // set volume + + bx lr + +/**************************************************************************** + * mmMixerSetPan( channel, panning ) + * + * Set channel panning + ****************************************************************************/ + .thumb_func +mmMixerSetPan: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r2 // + + strb r1, [r0, #CHN_PAN] // set panning + bx lr + +/**************************************************************************** + * mmMixerInit( system ) + * + * Initialize mixer + ****************************************************************************/ + .thumb_func +mmMixerInit: + + ldr r2,=mm_mixbuffer + ldr r1, [r0,#MM_GBA_SYSTEM_ACH_COUNT] + str r1, [r2,#16] + + mov r3, #CHN_SIZE + mul r1, r3 + ldr r3, [r0,#MM_GBA_SYSTEM_MIXCH] + str r3, [r2,#4] + add r3, r1 + str r3, [r2,#20] + ldr r1, [r0,#MM_GBA_SYSTEM_MIXMEM] + str r1, [r2,#0] + ldr r1, [r0,#MM_GBA_SYSTEM_WAVEMEM] + str r1, [r2,#8] + ldr r1, [r0,#MM_GBA_SYSTEM_MODE] + lsl r1, #1 + adr r3, mp_mixing_lengths + ldrh r3, [r3,r1] + str r3, [r2,#12] + adr r3, mp_rate_scales + ldrh r3, [r3, r1] + str r3, [r2, #24] + adr r3, mp_timing_sheet + ldrh r3, [r3, r1] + str r3, [r2, #28] + adr r3, mp_bpm_divisors + lsl r1, #1 + ldr r3, [r3,r1] + + ldr r2,=mm_bpmdv + str r3, [r2,#0] + + + ldr r0,=mm_wavebuffer @ clear wave buffer + ldr r0,[r0] + ldr r1,=mm_mixlen + ldr r1, [r1] + mov r2, #0 @ .. +.mpi_loop1: @ .. + stmia r0!, {r2} @ .. + sub r1, r1, #1 @ .. + bne .mpi_loop1 @ .. + + ldr r0,=mp_mix_seg @ reset mixing segment + strb r2, [r0] @ .. + + ldr r0,=mm_mixchannels @ disable mixing channels + ldr r1,[r0,#12]@ nchannels + ldr r0,[r0] + ldr r3,=1<<31 +.mpi_loop2: + str r3, [r0, #CHN_SRC] + add r0, #CHN_SIZE + sub r1, #1 + bne .mpi_loop2 + + ldr r0,=mmVBlank @ enable vblank routine + ldr r1,=0xE1A00000 @ .. + str r1, [r0] @ .. + + ldr r0,=REG_SGFIFOA @ clear fifo data + str r2, [r0] @ .. + str r2, [r0, #4] @ .. + ldr r0,=REG_SOUNDCNT_H @ reset direct sound + strh r2, [r0] @ .. + ldr r1,=0x9A0C @ setup sound [DIRECT SOUND A/B reset,timer0,A=left,B=right,volume=100%] + strh r1, [r0] @ .. + ldr r0,=REG_DMA1SAD @ setup DMA source addresses (playback buffers) + ldr r1,=mm_wavebuffer + ldr r2, [r1, #4]@mixlen + ldr r1, [r1] + + @ldr r1,=mp_playbuffer_l @ .. + str r1, [r0] @ .. + + add r1,r2 + add r1,r2 + +@ ldr r1,=mp_playbuffer_r @ .. + str r1, [r0, #12] @ .. + + ldr r1,=REG_SGFIFOA @ setup DMA destination (sound fifo) + str r1, [r0, #4] @ .. + add r1, #4 @ .. + str r1, [r0, #16] @ .. + + ldr r1,=0xB6000000 @ enable DMA (enable,fifo request,32-bit,repeat) + str r1, [r0, #8] @ .. + str r1, [r0, #20] @ .. + + ldr r0,=REG_SOUNDCNT_X @ master sound enable + mov r1, #0x80 @ .. + strh r1, [r0] @ .. + + ldr r0,=REG_VCOUNT @ wait for new frame +.mpi_vsync: @ .. + ldrh r1, [r0] @ skip current vblank period + cmp r1, #160 @ .. + bge .mpi_vsync @ .. +.mpi_vsync2: + ldrh r1, [r0] @ wait for new one + cmp r1, #160 @ .. + blt .mpi_vsync2 @ .. + +.mpi_vsync_2: @ pass#2 + ldrh r1, [r0] @ skip current vblank period + cmp r1, #160 @ .. + bge .mpi_vsync_2 @ .. +.mpi_vsync2_2: + ldrh r1, [r0] @ wait for new one + cmp r1, #160 @ .. + blt .mpi_vsync2_2 @ .. + + ldr r0,=REG_TM0CNT @ enable sampling timer + ldr r1,=mm_timerfreq + ldr r1,[r1] + mov r2, #0x80 + lsl r2, #16 + orr r1, r2 + @ldr r1,=(-MP_TIMERFREQ&0xFFFF) | (0x80<<16) @ .. + str r1, [r0] @ .. + bx lr @ finished + + +// round(rate / 59.737) +.align 2 +mp_mixing_lengths: + .hword 136, 176, 224, 264, 304, 352, 448, 528 + @ 8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz + +.align 2 +//mp_freq_scales: @ (16khz -> real) +// .hword 33056, 25536, 20064, 17024, 14784, 12768 + +// 15768*16384 / rate +mp_rate_scales: + .hword 31812, 24576, 19310, 16384, 14228, 12288, 9655, 8192 + @ 8khz, 10khz, 13khz, 16khz, 18khz, 21khz, 27khz, 32khz + @ 8121, 10512, 13379, 15768, 18157, 21024, 26758, 31536, + +.align 2 +// gbaclock / rate +mp_timing_sheet: + .hword -2066,-1596,-1254,-1064, -924, -798, -627, -532 + @ 8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz + +.align 2 +// rate * 2.5 +mp_bpm_divisors: + .word 20302,26280,33447,39420,45393,52560,66895,78840 + + +.end diff --git a/libs/maxmod/mm_types.h b/libs/maxmod/mm_types.h new file mode 100644 index 0000000..222ff5e --- /dev/null +++ b/libs/maxmod/mm_types.h @@ -0,0 +1,327 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> 32768 (HZ) + mm_word sampling_rate; + +// number of samples to buffer + mm_word buffer_length; + +// pointer to filling routine + mm_stream_func callback; + +// stream format (mm_stream_formats) + mm_word format; + +// hardware timer selection (mm_stream_timers) + mm_word timer; + +// if set, user must call mmStreamUpdate manually + mm_bool manual; + +//----------------------------------------------------------------------------- +} mm_stream; +//----------------------------------------------------------------------------- + +typedef struct t_mmlayer +{ + +// current tick count + mm_byte tick; + +// current row being played + mm_byte row; + +// module sequence position + mm_byte position; + +// number of rows in current pattern + mm_byte nrows; + +// global volume multiplier + mm_byte global_volume; + +// speed of module (ticks/row) + mm_byte speed; + +// module is active + mm_byte active; + +// tempo of module + mm_byte bpm; + +//----------------------------------------------------------------------------- +} mm_modlayer; +//----------------------------------------------------------------------------- + +typedef struct tmm_voice +{ + +// data source information + mm_addr source; // address to sample data + mm_word length; // length of sample data OR loop length (expressed in WORDS) + mm_hword loop_start; // loop start position (expressed in WORDS) + +// frequency divider + mm_hword timer; + +// update flags + mm_byte flags; + +// source format + mm_byte format; // 0: 8-bit + // 1: 16-bit + // 2: adpcm +// repeat mode + mm_byte repeat; // 0: manual + // 1: forward loop + // 2: one shot + +// volume + divider setting + mm_byte volume; // 0->127 + mm_byte divider; // 0->3 = /1, /2, /4, /16 + +// panning setting + mm_byte panning; // 0->127 + +// index of voice + mm_byte index; // 0->15 + +// pad to 20 bytes + mm_byte reserved[1]; + +//----------------------------------------------------------------------------- +} mm_voice; +//----------------------------------------------------------------------------- + +enum { + MMVF_FREQ =2, // update frequency when this flag is set + MMVF_VOLUME =4, // update volume + MMVF_PANNING =8, // update panning + MMVF_SOURCE =16, // update source and start note + MMVF_STOP =32 // stop voice (cut sound) +}; + +//----------------------------------------------------------------------------- + +#endif diff --git a/libs/maxmod/mp_defs.inc b/libs/maxmod/mp_defs.inc new file mode 100644 index 0000000..7716ef9 --- /dev/null +++ b/libs/maxmod/mp_defs.inc @@ -0,0 +1,117 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include +#include "gbaregs.h" +#include "intr.h" +#include "debug.h" +#include "util.h" + +uint16_t vblperf_color[] = { + /* grn blue cyan yellow orng red purple d.green purple ... */ + /* 60 30 20 15 12 10 8.5 7.5 ... */ + 0x3e0, 0xf863, 0xffc0, 0x3ff, 0x1ff, 0x001f, 0xf81f, 0x1e0, 0xf81f, 0xf81f, 0xf81f +}; + +void vblperf_setcolor(int palidx) +{ + vblperf_palptr = (uint16_t*)CRAM_BG_ADDR + palidx; +} + + +uint32_t panic_regs[16]; +void get_panic_regs(void); + +void panic(void *pc, const char *fmt, ...) +{ + int y; + va_list ap; + uint32_t *reg; + + get_panic_regs(); + + intr_disable(); + REG_DISPCNT = 4 | DISPCNT_BG2; + + set_bg_color(0, 31, 0, 0); + set_bg_color(0xff, 31, 31, 31); + + fillblock_16byte((void*)VRAM_LFB_FB0_ADDR, 0, 240 * 160 / 16); + + fillblock_16byte((unsigned char*)VRAM_LFB_FB0_ADDR + 240 * 3, 0xffffffff, 240 / 16); + dbg_drawstr(44, 0, " Panic at %p ", pc); + + va_start(ap, fmt); + y = dbg_vdrawstr(0, 12, fmt, ap) + 8; + va_end(ap); + + fillblock_16byte((unsigned char*)VRAM_LFB_FB0_ADDR + 240 * (y + 4), 0xffffffff, 240 / 16); + y += 8; + + reg = panic_regs; + y = dbg_drawstr(0, y, " r0 %08x r1 %08x\n r2 %08x r3 %08x\n r4 %08x r5 %08x\n r6 %08x r7 %08x\n", + reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]); + y = dbg_drawstr(0, y, " r8 %08x r9 %08x\nr10 %08x r11 %08x\n ip %08x sp %08x\n lr %08x pc %08x\n", + reg[8], reg[9], reg[10], reg[11], reg[12], reg[13], reg[14], reg[15]); + + /* stop any sound/music playback */ + REG_SOUNDCNT_H = SCNT_DSA_CLRFIFO | SCNT_DSB_CLRFIFO; + REG_TMCNT_H(1) &= ~TMCNT_EN; + REG_DMA1CNT_H = 0; + REG_DMA2CNT_H = 0; + + for(;;); +} + +void dbg_drawglyph(int x, int y, int c) +{ + int i; + uint16_t pp; + unsigned char row; + uint16_t *ptr = (uint16_t*)VRAM_LFB_FB0_ADDR + (y << 7) - (y << 3) + (x >> 1); + unsigned char *fnt = font_8x8 + ((c & 0xff) << 3); + + for(i=0; i<8; i++) { + row = *fnt++; + pp = row & 0x80 ? 0xff : 0; + *ptr++ = pp | (row & 0x40 ? 0xff00 : 0); + pp = row & 0x20 ? 0xff : 0; + *ptr++ = pp | (row & 0x10 ? 0xff00 : 0); + pp = row & 0x08 ? 0xff : 0; + *ptr++ = pp | (row & 0x04 ? 0xff00 : 0); + pp = row & 0x02 ? 0xff : 0; + *ptr++ = pp | (row & 0x01 ? 0xff00 : 0); + ptr += 120 - 4; + } +} + +int dbg_vdrawstr(int x, int y, const char *fmt, va_list ap) +{ + int startx, c; + char buf[128]; + char *ptr = buf; + + vsnprintf(buf, sizeof buf, fmt, ap); + + startx = x; + while(*ptr) { + if(y >= 160) break; + + c = *ptr++; + switch(c) { + case '\n': + y += 8; + case '\r': + x = startx; + break; + + default: + dbg_drawglyph(x, y, c); + x += 8; + if(x >= 240 - 8) { + while(*ptr && isspace(*ptr)) ptr++; + x = 0; + y += 8; + } + } + } + + return y; +} + +int dbg_drawstr(int x, int y, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = dbg_vdrawstr(x, y, fmt, ap); + va_end(ap); + return res; +} + +#ifdef EMUBUILD +__attribute__((target("arm"))) +void emuprint(const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof buf, fmt, ap); + va_end(ap); + + asm volatile( + "mov r0, %0\n\t" + "swi 0xff0000\n\t" : + : "r" (buf) + : "r0" + ); +} +#else +void emuprint(const char *fmt, ...) +{ +} +#endif diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..921fd12 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,39 @@ +#ifndef DEBUG_H_ +#define DEBUG_H_ + +#include +#include "util.h" + +extern unsigned char font_8x8[]; + +extern uint16_t vblperf_color[]; +uint16_t *vblperf_palptr; +volatile int vblperf_count; + +void vblperf_setcolor(int palidx); + +#ifdef VBLBAR +#define vblperf_begin() \ + do { \ + *vblperf_palptr = 0; \ + vblperf_count = 0; \ + } while(0) + +#define vblperf_end() \ + do { \ + *vblperf_palptr = vblperf_color[vblperf_count]; \ + } while(0) +#else +#define vblperf_begin() +#define vblperf_end() +#endif + +void panic(void *pc, const char *fmt, ...) __attribute__((noreturn)); + +void dbg_drawglyph(int x, int y, int c); +int dbg_drawstr(int x, int y, const char *fmt, ...); +int dbg_vdrawstr(int x, int y, const char *fmt, va_list ap); + +void emuprint(const char *fmt, ...); + +#endif /* DEBUG_H_ */ diff --git a/src/dma.c b/src/dma.c new file mode 100644 index 0000000..ba23ab7 --- /dev/null +++ b/src/dma.c @@ -0,0 +1,62 @@ +#include "dma.h" + +/* DMA Options */ +#define DMA_ENABLE 0x80000000 +#define DMA_INT_ENABLE 0x40000000 +#define DMA_TIMING_IMMED 0x00000000 +#define DMA_TIMING_VBLANK 0x10000000 +#define DMA_TIMING_HBLANK 0x20000000 +#define DMA_TIMING_DISPSYNC 0x30000000 +#define DMA_16 0x00000000 +#define DMA_32 0x04000000 +#define DMA_REPEAT 0x02000000 +#define DMA_SRC_INC 0x00000000 +#define DMA_SRC_DEC 0x00800000 +#define DMA_SRC_FIX 0x01000000 +#define DMA_DST_INC 0x00000000 +#define DMA_DST_DEC 0x00200000 +#define DMA_DST_FIX1 0x00400000 +#define DMA_DST_RELOAD 0x00600000 + +/* DMA Register Parts */ +#define DMA_SRC 0 +#define DMA_DST 1 +#define DMA_CTRL 2 + +static volatile uint32_t *reg_dma[4] = {(void*)0x040000b0, (void*)0x040000bc, (void*)0x040000c8, (void*)0x040000d4 }; + +/* --- perform a copy of words or halfwords using DMA --- */ + +void dma_copy32(int channel, void *dst, void *src, int words, unsigned int flags) +{ + reg_dma[channel][DMA_SRC] = (uint32_t)src; + reg_dma[channel][DMA_DST] = (uint32_t)dst; + reg_dma[channel][DMA_CTRL] = words | flags | DMA_32 | DMA_ENABLE; +} + +void dma_copy16(int channel, void *dst, void *src, int halfwords, unsigned int flags) +{ + reg_dma[channel][DMA_SRC] = (uint32_t)src; + reg_dma[channel][DMA_DST] = (uint32_t)dst; + reg_dma[channel][DMA_CTRL] = halfwords | flags | DMA_16 | DMA_ENABLE; +} + +/* --- fill a buffer with an ammount of words and halfwords using DMA --- */ + +static uint32_t fill[4]; + +void dma_fill32(int channel, void *dst, uint32_t val, int words) +{ + fill[channel] = val; + reg_dma[channel][DMA_SRC] = (uint32_t)(fill + channel); + reg_dma[channel][DMA_DST] = (uint32_t)dst; + reg_dma[channel][DMA_CTRL] = words | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_32 | DMA_ENABLE; +} + +void dma_fill16(int channel, void *dst, uint16_t val, int halfwords) +{ + fill[channel] = val; + reg_dma[channel][DMA_SRC] = (uint32_t)(fill + channel); + reg_dma[channel][DMA_DST] = (uint32_t)dst; + reg_dma[channel][DMA_CTRL] = halfwords | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_16 | DMA_ENABLE; +} diff --git a/src/dma.h b/src/dma.h new file mode 100644 index 0000000..7ff7606 --- /dev/null +++ b/src/dma.h @@ -0,0 +1,12 @@ +#ifndef DMA_H_ +#define DMA_H_ + +#include + +void dma_copy32(int channel, void *dst, void *src, int words, unsigned int flags); +void dma_copy16(int channel, void *dst, void *src, int halfwords, unsigned int flags); + +void dma_fill32(int channel, void *dst, uint32_t val, int words); +void dma_fill16(int channel, void *dst, uint16_t val, int halfwords); + +#endif /* DMA_H_ */ diff --git a/src/font8x8.c b/src/font8x8.c new file mode 100644 index 0000000..365044f --- /dev/null +++ b/src/font8x8.c @@ -0,0 +1,2565 @@ +/* Font data derived from Linux 2.6.7: drivers/video/console/font_8x8.c */ + +unsigned char font_8x8[] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xce, /* 11001110 */ + 0x7c, /* 01111100 */ + 0x0e, /* 00001110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x8c, /* 10001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + + /* 96 0x60 '`' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf8, /* 11111000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + + /* 104 0x68 'h' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + + /* 107 0x6b 'k' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x4c, /* 01001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 'ˆ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '™' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c 'œ' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e 'ž' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f 'Ÿ' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '¬' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '­' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 'é' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee 'î' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc 'ü' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..b290634 --- /dev/null +++ b/src/game.h @@ -0,0 +1,9 @@ +#ifndef GAME_H_ +#define GAME_H_ + +void (*screen_vblank)(void); + +void menuscr(void); +void gamescr(void); + +#endif /* GAME_H_ */ diff --git a/src/gamescr.c b/src/gamescr.c new file mode 100644 index 0000000..cacb40d --- /dev/null +++ b/src/gamescr.c @@ -0,0 +1,69 @@ +#include +#include +#include "gbaregs.h" +#include "game.h" +#include "dma.h" +#include "util.h" +#include "intr.h" +#include "input.h" +#include "sprite.h" +#include "debug.h" + +static void draw(void); +static void vblank(void); + +static int nframes, num_vbl, backbuf; +static uint16_t *vram[] = { (uint16_t*)VRAM_LFB_FB0_ADDR, (uint16_t*)VRAM_LFB_FB1_ADDR }; +static uint16_t bnstate; + + +void gamescr(void) +{ + int i; + + REG_DISPCNT = 4 | DISPCNT_BG2 | DISPCNT_OBJ | DISPCNT_FB1; + + vblperf_setcolor(0xff);//192); + + fillblock_16byte(vram[0], 0xffffffff, 240 * 160 / 16); + fillblock_16byte(vram[1], 0xffffffff, 240 * 160 / 16); + + mask(INTR_VBLANK); + screen_vblank = vblank; + unmask(INTR_VBLANK); + + nframes = 0; + for(;;) { + backbuf = ++nframes & 1; + + bnstate = ~REG_KEYINPUT; + + draw(); + + vblperf_end(); + wait_vblank(); + present(backbuf); + vblperf_begin(); + } +} + +static void draw(void) +{ + int i, j; + uint16_t pix; + uint16_t *fb = vram[backbuf]; + + for(i=0; i<160; i++) { + for(j=0; j<240/2; j++) { + pix = ((i^j) << 1) & 0xff; + pix |= (i^j) << 9; + *fb++ = pix; + } + } +} + +__attribute__((noinline, target("arm"), section(".iwram"))) +static void vblank(void) +{ + num_vbl++; +} diff --git a/src/gbaregs.h b/src/gbaregs.h new file mode 100644 index 0000000..3396cc9 --- /dev/null +++ b/src/gbaregs.h @@ -0,0 +1,365 @@ +#ifndef GBAREGS_H_ +#define GBAREGS_H_ + +#include + +#define VRAM_START_ADDR 0x6000000 +#define VRAM_BG_ADDR VRAM_START_ADDR +#define VRAM_OBJ_ADDR 0x6010000 +#define VRAM_LFB_OBJ_ADDR 0x6014000 +#define VRAM_LFB_FB0_ADDR VRAM_START_ADDR +#define VRAM_LFB_FB1_ADDR 0x600a000 + +/* address of character data block x (4 possible blocks, 16k each) */ +#define VRAM_CHR_BLOCK_ADDR(x) (VRAM_START_ADDR + ((x) << 14)) +/* address of screen data block x (32 possible blocks, 2k each) */ +#define VRAM_SCR_BLOCK_ADDR(x) (VRAM_START_ADDR + ((x) << 11)) + +/* fields of a background tile in screen memory */ +#define BGTILE_HFLIP 0x0400 +#define BGTILE_VFLIP 0x0800 +#define BGTILE_PAL(x) ((uint16_t)(x) << 12) + +/* color palette ram addresses for backgrounds and sprites */ +#define CRAM_BG_ADDR 0x5000000 +#define CRAM_OBJ_ADDR 0x5000200 + +/* OAM table */ +#define OAM_ADDR 0x7000000 + +/* interrupt handler */ +#define INTR_VECTOR (*(volatile uint32_t*)0x3007ffc) + +/* battery backed RAM address */ +#define SRAM_ADDR 0xe000000 + +/* I/O space */ + +#define REG_BASE 0x4000000 +#define REG8(x) (*(volatile uint8_t*)(REG_BASE + (x))) +#define REG16(x) (*(volatile uint16_t*)(REG_BASE + (x))) +#define REG32(x) (*(volatile uint32_t*)(REG_BASE + (x))) + +/* ---- display registers ---- */ +#define REG_DISPCNT REG16(0x00) +#define REG_GREENSWAP REG16(0x02) +#define REG_DISPSTAT REG16(0x04) +#define REG_VCOUNT REG16(0x06) +#define REG_BG0CNT REG16(0x08) +#define REG_BG1CNT REG16(0x0a) +#define REG_BG2CNT REG16(0x0c) +#define REG_BG3CNT REG16(0x0e) +/* scrolling registers */ +#define REG_BG0HOFS REG16(0x10) +#define REG_BG0VOFS REG16(0x12) +#define REG_BG1HOFS REG16(0x14) +#define REG_BG1VOFS REG16(0x16) +#define REG_BG2HOFS REG16(0x18) +#define REG_BG2VOFS REG16(0x1a) +#define REG_BG3HOFS REG16(0x1c) +#define REG_BG3VOFS REG16(0x1e) +/* BG rotation and scaling registers */ +#define REG_BG2PA REG16(0x20) +#define REG_BG2PB REG16(0x22) +#define REG_BG2PC REG16(0x24) +#define REG_BG2PD REG16(0x26) +#define REG_BG2X REG32(0x28) +#define REG_BG2Y REG32(0x2c) +#define REG_BG3PA REG16(0x30) +#define REG_BG3PB REG16(0x32) +#define REG_BG3PC REG16(0x34) +#define REG_BG3PD REG16(0x36) +#define REG_BG3X REG32(0x38) +#define REG_BG3Y REG32(0x3c) +/* window registers */ +#define REG_WIN0H REG16(0x40) +#define REG_WIN1H REG16(0x42) +#define REG_WIN0V REG16(0x44) +#define REG_WIN1V REG16(0x46) +#define REG_WININ REG16(0x48) +#define REG_WINOUT REG16(0x4a) + +#define REG_MOSAIC REG16(0x4c) +/* color effects */ +#define REG_BLDCNT REG16(0x50) +#define REG_BLDALPHA REG16(0x52) +#define REG_BLDY REG16(0x54) + +/* ---- sound registers ---- */ +#define REG_SOUND1CNT_L REG16(0x60) +#define REG_SOUND1CNT_H REG16(0x62) +#define REG_SOUND1CNT_X REG16(0x64) +#define REG_SOUND2CNT_L REG16(0x68) +#define REG_SOUND2CNT_H REG16(0x6c) +#define REG_SOUND3CNT_L REG16(0x70) +#define REG_SOUND3CNT_H REG16(0x72) +#define REG_SOUND3CNT_X REG16(0x74) +#define REG_SOUND4CNT_L REG16(0x78) +#define REG_SOUND4CNT_H REG16(0x7c) +#define REG_SOUNDCNT_L REG16(0x80) +#define REG_SOUNDCNT_H REG16(0x82) +#define REG_SOUNDCNT_X REG16(0x84) +#define REG_SOUNDBIAS REG16(0x88) +#define WAVE_RAM_PTR ((unsigned char*)(REG_BASE + 0x90)) +#define REG_FIFO_A REG32(0xa0) +#define REG_FIFO_B REG32(0xa4) +#define FIFO_A_PTR ((unsigned char*)(REG_BASE + 0xa0)) +#define FIFO_B_PTR ((unsigned char*)(REG_BASE + 0xa4)) + +/* ---- DMA registers ---- */ +#define REG_DMA0SAD REG32(0xb0) +#define REG_DMA0DAD REG32(0xb4) +#define REG_DMA0CNT REG32(0xb8) +#define REG_DMA0CNT_L REG16(0xb8) +#define REG_DMA0CNT_H REG16(0xba) +#define REG_DMA1SAD REG32(0xbc) +#define REG_DMA1DAD REG32(0xc0) +#define REG_DMA1CNT REG32(0xc4) +#define REG_DMA1CNT_L REG16(0xc4) +#define REG_DMA1CNT_H REG16(0xc6) +#define REG_DMA2SAD REG32(0xc8) +#define REG_DMA2DAD REG32(0xcc) +#define REG_DMA2CNT REG32(0xd0) +#define REG_DMA2CNT_L REG16(0xd0) +#define REG_DMA2CNT_H REG16(0xd2) +#define REG_DMA3SAD REG32(0xd4) +#define REG_DMA3DAD REG32(0xd8) +#define REG_DMA3CNT REG32(0xdc) +#define REG_DMA3CNT_L REG16(0xdc) +#define REG_DMA3CNT_H REG16(0xde) + +/* ---- timer registers ---- */ +#define REG_TM0CNT_L REG16(0x100) +#define REG_TM0CNT_H REG16(0x102) +#define REG_TM1CNT_L REG16(0x104) +#define REG_TM1CNT_H REG16(0x106) +#define REG_TM2CNT_L REG16(0x108) +#define REG_TM2CNT_H REG16(0x10a) +#define REG_TM3CNT_L REG16(0x10c) +#define REG_TM3CNT_H REG16(0x10e) + +#define REG_TMCNT_L(x) REG16(0x100 + ((x) << 2)) +#define REG_TMCNT_H(x) REG16(0x102 + ((x) << 2)) + +/* ---- communication registers (serial/joybus/gpio) ---- */ +#define REG_SIODATA32 REG32(0x120) +#define REG_SIOMULTI0 REG16(0x120) +#define REG_SIOMULTI1 REG16(0x122) +#define REG_SIOMULTI2 REG16(0x124) +#define REG_SIOMULTI3 REG16(0x126) +#define REG_SIOCNT REG16(0x128) +#define REG_SIOMLT_SEND REG16(0x12a) +#define REG_SIODATA8 REG16(0x12a) +#define REG_RCNT REG16(0x134) +#define REG_JOYCNT REG16(0x140) +#define REG_JOY_RECV REG32(0x150) +#define REG_JOY_TRANS REG32(0x154) +#define REG_JOYSTAT REG16(0x158) + +/* ---- keypad registers ---- */ +#define REG_KEYINPUT REG16(0x130) +#define REG_KEYCNT REG16(0x132) + +/* ---- interrupts ---- */ +#define REG_IE REG16(0x200) +#define REG_IF REG16(0x202) +#define REG_WAITCNT REG16(0x204) +#define REG_IME REG16(0x208) + +#define REG_POSTFLG REG8(0x300) +#define REG_HALTCNT REG8(0x301) +#define REG_INTMEMCNT REG32(0x800) + +/* REG_DISPSTAT bits */ +#define DISPSTAT_VBLANK 0x01 +#define DISPSTAT_HBLANK 0x02 +#define DISPSTAT_VMATCH 0x04 +#define DISPSTAT_IEN_VBLANK 0x08 +#define DISPSTAT_IEN_HBLANK 0x10 +#define DISPSTAT_IEN_VMATCH 0x20 +#define DISPSTAT_VCOUNT(x) ((uint16_t)(x) << 8) + +/* REG_DISPCNT bits */ +#define DISPCNT_MODE(x) (x) +#define DISPCNT_FB1 0x0010 +#define DISPCNT_HBLANK_OBJPROC 0x0020 +#define DISPCNT_OBJMAP_1D 0x0040 +#define DISPCNT_FORCE_BLANK 0x0080 +#define DISPCNT_BG0 0x0100 +#define DISPCNT_BG1 0x0200 +#define DISPCNT_BG2 0x0400 +#define DISPCNT_BG3 0x0800 +#define DISPCNT_OBJ 0x1000 +#define DISPCNT_WIN0 0x2000 +#define DISPCNT_WIN1 0x4000 +#define DISPCNT_WINOBJ 0x8000 + +/* REG_BGXCNT bits */ +#define BGCNT_PRIO(x) ((uint16_t)(x)) +#define BGCNT_CHR_BASE(x) ((uint16_t)(x) << 2) +#define BGCNT_MOSAIC 0x0040 +#define BGCNT_256COL 0x0080 +#define BGCNT_SCR_BASE(x) ((uint16_t)(x) << 8) +#define BGCNT_WRAP 0x2000 + +#define BGCNT_SZ(x) ((uint16_t)(x) << 14) +#define BGCNT_SZ_TX_256X256 BGCNT_SZ(0) +#define BGCNT_SZ_RS_128X128 BGCNT_SZ(0) +#define BGCNT_SZ_TX_512X256 BGCNT_SZ(1) +#define BGCNT_SZ_RS_256X256 BGCNT_SZ(1) +#define BGCNT_SZ_TX_256X512 BGCNT_SZ(2) +#define BGCNT_SZ_RS_512X512 BGCNT_SZ(2) +#define BGCNT_SZ_TX_512X512 BGCNT_SZ(3) +#define BGCNT_SZ_RS_1024X1024 BGCNT_SZ(3) + +/* REG_BLDCNT bits */ +#define BLDCNT_A_BG0 0x0001 +#define BLDCNT_A_BG1 0x0002 +#define BLDCNT_A_BG2 0x0004 +#define BLDCNT_A_BG3 0x0008 +#define BLDCNT_A_OBJ 0x0010 +#define BLDCNT_A_BACKDROP 0x0020 +#define BLDCNT_B_BG0 0x0100 +#define BLDCNT_B_BG1 0x0200 +#define BLDCNT_B_BG2 0x0400 +#define BLDCNT_B_BG3 0x0800 +#define BLDCNT_B_OBJ 0x1000 +#define BLDCNT_B_BACKDROP 0x2000 + +#define BLDCNT_ALPHA 0x0040 +#define BLDCNT_BRIGHTEN 0x0080 +#define BLDCNT_DARKEN 0x00c0 + +/* REG_IF bits */ +#define IF_VBLANK 0x0001 +#define IF_HBLANK 0x0002 +#define IF_VMATCH 0x0004 +#define IF_TIMER0 0x0008 +#define IF_TIMER1 0x0010 +#define IF_TIMER2 0x0020 +#define IF_TIMER3 0x0040 +#define IF_COMM 0x0080 +#define IF_DMA0 0x0100 +#define IF_DMA1 0x0200 +#define IF_DMA2 0x0400 +#define IF_DMA3 0x0800 +#define IF_KEY 0x1000 +#define IF_GPAK 0x2000 + +/* REG_TMXCNT bits */ +#define TMCNT_PRESCL_CLK1 0 +#define TMCNT_PRESCL_CLK64 1 +#define TMCNT_PRESCL_CLK256 2 +#define TMCNT_PRESCL_CLK1024 3 + +#define TMCNT_CASCADE 0x04 +#define TMCNT_IE 0x40 +#define TMCNT_EN 0x80 + +/* REG_KEY* bits */ +#define KEY_A 0x0001 +#define KEY_B 0x0002 +#define KEY_SELECT 0x0004 +#define KEY_START 0x0008 +#define KEY_RIGHT 0x0010 +#define KEY_LEFT 0x0020 +#define KEY_UP 0x0040 +#define KEY_DOWN 0x0080 +#define KEY_RT 0x0100 +#define KEY_LT 0x0200 + +#define KEYCNT_IE 0x4000 +#define KEYCNT_IAND 0x8000 + +/* REG_SOUNDCNT_L bits */ +#define SCNT_SS_LVOL(x) ((x) & 7) +#define SCNT_SS_RVOL(x) (((x) & 7) << 4) +#define SCNT_SS_VOL(x) (SCNT_SS_LVOL(x) | SCNT_SS_RVOL(x)) +#define SCNT_SS1_EN_R 0x0100 +#define SCNT_SS2_EN_R 0x0200 +#define SCNT_SS3_EN_R 0x0400 +#define SCNT_SS4_EN_R 0x0800 +#define SCNT_SS_EN_R(x) (SCNT_SS1_EN_R << (x)) +#define SCNT_SS1_EN_L 0x1000 +#define SCNT_SS2_EN_L 0x2000 +#define SCNT_SS3_EN_L 0x4000 +#define SCNT_SS4_EN_L 0x8000 +#define SCNT_SS_EN_L(x) (SCNT_SS1_EN_L << (x)) +#define SCNT_SS1_EN (SCNT_SS1_EN_R | SCNT_SS1_EN_L) +#define SCNT_SS2_EN (SCNT_SS2_EN_R | SCNT_SS2_EN_L) +#define SCNT_SS3_EN (SCNT_SS3_EN_R | SCNT_SS3_EN_L) +#define SCNT_SS4_EN (SCNT_SS4_EN_R | SCNT_SS4_EN_L) +#define SCNT_SS_EN(x) (SCNT_SS_EN_L(x) | SCNT_SS_EN_R(x)) + +#define SCNT_SS1 0 +#define SCNT_SS2 1 +#define SCNT_SS3 2 +#define SCNT_SS4 3 + +/* REG_SOUNDCNT_X bits */ +#define SCNT_MASTER_EN 0x0080 + +/* REG_SOUNDCNT_H bits */ +#define SCNT_SS_VOL_QRT 0x0000 +#define SCNT_SS_VOL_HALF 0x0001 +#define SCNT_SS_VOL_FULL 0x0002 +#define SCNT_DSA_VOL_HALF 0 +#define SCNT_DSA_VOL_FULL 0x0004 +#define SCNT_DSB_VOL_HALF 0 +#define SCNT_DSB_VOL_FULL 0x0008 +#define SCNT_DSA_EN_R 0x0100 +#define SCNT_DSA_EN_L 0x0200 +#define SCNT_DSA_TIMER0 0 +#define SCNT_DSA_TIMER1 0x0400 +#define SCNT_DSA_CLRFIFO 0x0800 +#define SCNT_DSB_EN_R 0x1000 +#define SCNT_DSB_EN_L 0x2000 +#define SCNT_DSB_TIMER0 0 +#define SCNT_DSB_TIMER1 0x4000 +#define SCNT_DSB_CLRFIFO 0x8000 + +/* REG_DMAxCNT_H bits */ +#define DMACNTH_DST_INC 0 +#define DMACNTH_DST_DEC 0x0020 +#define DMACNTH_DST_FIXED 0x0040 +#define DMACNTH_INC_RELOAD 0x0060 +#define DMACNTH_SRC_INC 0 +#define DMACNTH_SRC_DEC 0x0080 +#define DMACNTH_SRC_FIXED 0x0100 +#define DMACNTH_REPEAT 0x0200 +#define DMACNTH_16BIT 0 +#define DMACNTH_32BIT 0x0400 +#define DMACNTH_VBLANK 0x1000 +#define DMACNTH_HBLANK 0x2000 +#define DMACNTH_SOUND 0x3000 +#define DMACNTH_IEN 0x4000 +#define DMACNTH_EN 0x8000 + +#define DMACNT_DST_INC 0 +#define DMACNT_DST_DEC 0x00200000 +#define DMACNT_DST_FIXED 0x00400000 +#define DMACNT_INC_RELOAD 0x00600000 +#define DMACNT_SRC_INC 0 +#define DMACNT_SRC_DEC 0x00800000 +#define DMACNT_SRC_FIXED 0x01000000 +#define DMACNT_REPEAT 0x02000000 +#define DMACNT_16BIT 0 +#define DMACNT_32BIT 0x04000000 +#define DMACNT_VBLANK 0x10000000 +#define DMACNT_HBLANK 0x20000000 +#define DMACNT_SOUND 0x30000000 +#define DMACNT_IEN 0x40000000 +#define DMACNT_EN 0x80000000 + +/* REG_WAITCNT bits */ +#define WAITCNT_ROM_4_2 0x0000 +#define WAITCNT_ROM_3_2 0x0004 +#define WAITCNT_ROM_2_2 0x0008 +#define WAITCNT_ROM_8_2 0x000c +#define WAITCNT_ROM_4_1 0x0010 +#define WAITCNT_ROM_3_1 0x0014 +#define WAITCNT_ROM_2_1 0x0018 +#define WAITCNT_ROM_8_1 0x001c +#define WAITCNT_PREFETCH 0x4000 + +#endif /* GBAREGS_H_ */ diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..6a66dd1 --- /dev/null +++ b/src/input.c @@ -0,0 +1,39 @@ +#include "input.h" +#include "gbaregs.h" +#include "intr.h" + +static void keyintr(void); + +static uint16_t bnstate; + +void select_input(uint16_t bmask) +{ + bnstate = 0; + + mask(INTR_KEY); + if(bmask) { + REG_KEYCNT = bmask | KEYCNT_IE; + interrupt(INTR_KEY, keyintr); + unmask(INTR_KEY); + } else { + REG_KEYCNT = 0; + interrupt(INTR_KEY, 0); + } +} + +uint16_t get_input(void) +{ + uint16_t s; + + mask(INTR_KEY); + s = bnstate; + bnstate = 0; + unmask(INTR_KEY); + + return s; +} + +static void keyintr(void) +{ + bnstate |= ~REG_KEYINPUT; +} diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..3ed22a0 --- /dev/null +++ b/src/input.h @@ -0,0 +1,24 @@ +#ifndef INPUT_H_ +#define INPUT_H_ + +#include + +enum { + BN_A = 0x0001, + BN_B = 0x0002, + BN_SELECT = 0x0004, + BN_START = 0x0008, + BN_RIGHT = 0x0010, + BN_LEFT = 0x0020, + BN_UP = 0x0040, + BN_DOWN = 0x0080, + BN_RT = 0x0100, + BN_LT = 0x0200 +}; + +#define BN_DPAD (BN_RIGHT | BN_LEFT | BN_UP | BN_DOWN) + +void select_input(uint16_t bmask); +uint16_t get_input(void); + +#endif /* INPUT_H_ */ diff --git a/src/intr.c b/src/intr.c new file mode 100644 index 0000000..5858bf1 --- /dev/null +++ b/src/intr.c @@ -0,0 +1,31 @@ +#include "intr.h" + +#define MAX_INTR 14 +static void (*intr_table[MAX_INTR])(void); + +__attribute__ ((target("arm"), section(".iwram"))) +static void intr_handler(void) +{ + int i; + uint16_t iflags; + + iflags = REG_IF; + + for(i=0; i +#include "gbaregs.h" +#include "intr.h" +#include "debug.h" +#include "game.h" +#include "maxmod.h" + +static void vblank(void); +static void nopfunc(void); + +int main(void) +{ + int i; + volatile uint16_t *cptr; + + intr_init(); + + REG_WAITCNT = WAITCNT_PREFETCH | WAITCNT_ROM_2_1; + + cptr = (uint16_t*)CRAM_BG_ADDR; + for(i=0; i<256; i++) { + int c = i >> 3; + *cptr++ = c | ((c >> 1) << 10); + } + +#ifndef NOSOUND + mmInitDefault(sound_data, 8); + mmStart(MOD_POPCORN, MM_PLAY_LOOP); +#endif + + screen_vblank = nopfunc; + + intr_disable(); + interrupt(INTR_VBLANK, vblank); + REG_DISPSTAT |= DISPSTAT_IEN_VBLANK; + unmask(INTR_VBLANK); + + intr_enable(); + gamescr(); + + for(;;); + return 0; +} + +static void vblank(void) +{ + vblperf_count++; + + screen_vblank(); + +#ifndef NOSOUND + mmVBlank(); + mmFrame(); +#endif +} + +static void nopfunc(void) +{ +} diff --git a/src/menuscr.c b/src/menuscr.c new file mode 100644 index 0000000..dfbc8cb --- /dev/null +++ b/src/menuscr.c @@ -0,0 +1,5 @@ +#include "gbaregs.h" + +void menuscr(void) +{ +} diff --git a/src/polyfill.c b/src/polyfill.c new file mode 100644 index 0000000..18294f5 --- /dev/null +++ b/src/polyfill.c @@ -0,0 +1,303 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include "polyfill.h" +#include "debug.h" + +static unsigned char *fb; +static int fbwidth, fbheight; +static short scantab[2][160] __attribute__((section(".iwram"))); + +void polyfill_framebuffer(unsigned char *ptr, int w, int h) +{ + fb = ptr; + fbwidth = w; + fbheight = h; +} + +#define VNEXT(p) (((p) == vlast) ? varr : (p) + 1) +#define VPREV(p) ((p) == varr ? vlast : (p) - 1) +#define VSUCC(p, side) ((side) == 0 ? VNEXT(p) : VPREV(p)) + +void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col) +{ + int i, line, top, bot; + struct pvertex *vlast, *v, *vn; + int32_t x, y0, y1, dx, dy, slope, fx, fy; + short *tab, start, len; + unsigned char *fbptr; + uint16_t *pptr, pcol = ((uint16_t)col << 8) | (uint16_t)col; + + vlast = varr + vnum - 1; + top = fbheight; + bot = 0; + + for(i=0; iy == v->y) continue; + + if(vn->y > v->y) { + tab = scantab[0]; + } else { + tab = scantab[1]; + v = vn; + vn = varr + i; + } + + dx = vn->x - v->x; + dy = vn->y - v->y; + slope = (dx << 8) / dy; + + y0 = (v->y + 0x100) & 0xffffff00; /* start from the next scanline */ + fy = y0 - v->y; /* fractional part before the next scanline */ + fx = (fy * slope) >> 8; /* X adjust for the step to the next scanline */ + x = v->x + fx; /* adjust X */ + y1 = vn->y & 0xffffff00; /* last scanline of the edge <= vn->y */ + + line = y0 >> 8; + if(line < top) top = line; + if((y1 >> 8) > bot) bot = y1 >> 8; + + if(line > 0) tab += line; + + while(line <= (y1 >> 8) && line < fbheight) { + if(line >= 0) { + int val = x < 0 ? 0 : x >> 8; + *tab++ = val < fbwidth ? val : fbwidth - 1; + } + x += slope; + line++; + } + } + + fbptr = fb + top * fbwidth; + for(i=top; i<=bot; i++) { + start = scantab[0][i]; + len = scantab[1][i] - start; + + if(len > 0) { + if(start & 1) { + pptr = (uint16_t*)(fbptr + (start & 0xfffe)); + *pptr = (*pptr & 0xff) | ((uint16_t)col << 8); + len--; + start++; + } + pptr = (uint16_t*)(fbptr + start); + while(len > 1) { + *pptr++ = pcol; + len -= 2; + } + if(len) { + *pptr = (*pptr & 0xff00) | col; + } + } + fbptr += fbwidth; + } +} + + +/* ----- line drawing and clipping ------ */ +enum { + IN = 0, + LEFT = 1, + RIGHT = 2, + TOP = 4, + BOTTOM = 8 +}; + +static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax) +{ + int code = 0; + + if(x < xmin) { + code |= LEFT; + } else if(x > xmax) { + code |= RIGHT; + } + if(y < ymin) { + code |= TOP; + } else if(y > ymax) { + code |= BOTTOM; + } + return code; +} + +#define FIXMUL(a, b) (((a) * (b)) >> 8) +#define FIXDIV(a, b) (((a) << 8) / (b)) + +#define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t))) + +int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax) +{ + int oc_out; + + int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax); + int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax); + + long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax; + + if(!(oc0 | oc1)) return 1; /* both points are inside */ + + fx0 = *x0 << 8; + fy0 = *y0 << 8; + fx1 = *x1 << 8; + fy1 = *y1 << 8; + fxmin = xmin << 8; + fymin = ymin << 8; + fxmax = xmax << 8; + fymax = ymax << 8; + + for(;;) { + long x, y, t; + + if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */ + if(!(oc0 | oc1)) break; /* both points are inside */ + + oc_out = oc0 ? oc0 : oc1; + + if(oc_out & TOP) { + t = FIXDIV(fymin - fy0, fy1 - fy0); + x = LERP(fx0, fx1, t); + y = fymin; + } else if(oc_out & BOTTOM) { + t = FIXDIV(fymax - fy0, fy1 - fy0); + x = LERP(fx0, fx1, t); + y = fymax; + } else if(oc_out & LEFT) { + t = FIXDIV(fxmin - fx0, fx1 - fx0); + x = fxmin; + y = LERP(fy0, fy1, t); + } else {/*if(oc_out & RIGHT) {*/ + t = FIXDIV(fxmax - fx0, fx1 - fx0); + x = fxmax; + y = LERP(fy0, fy1, t); + } + + if(oc_out == oc0) { + fx0 = x; + fy0 = y; + oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax); + } else { + fx1 = x; + fy1 = y; + oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax); + } + } + + *x0 = fx0 >> 8; + *y0 = fy0 >> 8; + *x1 = fx1 >> 8; + *y1 = fy1 >> 8; + return 1; +} + +#ifdef ALT_LCLIP +#define PUTPIXEL(ptr) \ + do { \ + if(x0 >= 0 && x0 < fbwidth && y0 >= 0 && y0 < fbheight) { \ + uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \ + if((uint32_t)ptr & 1) { \ + *pptr = (*pptr & 0xff) | (color << 8); \ + } else { \ + *pptr = (*pptr & 0xff00) | color; \ + } \ + } \ + } while(0) +#else /* !ALT_LCLIP */ +#define PUTPIXEL(ptr) \ + do { \ + uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \ + if((uint32_t)ptr & 1) { \ + *pptr = (*pptr & 0xff) | (color << 8); \ + } else { \ + *pptr = (*pptr & 0xff00) | color; \ + } \ + } while(0) +#endif + +void draw_line(int x0, int y0, int x1, int y1, unsigned short color) +{ + int i, dx, dy, x_inc, y_inc, error; +#ifdef ALT_LCLIP + int y0inc; +#endif + unsigned char *fbptr = fb; + + fbptr += y0 * fbwidth + x0; + + dx = x1 - x0; + dy = y1 - y0; + + if(dx >= 0) { + x_inc = 1; + } else { + x_inc = -1; + dx = -dx; + } + if(dy >= 0) { + y_inc = fbwidth; +#ifdef ALT_LCLIP + y0inc = 1; +#endif + } else { + y_inc = -fbwidth; +#ifdef ALT_LCLIP + y0inc = -1; +#endif + dy = -dy; + } + + if(dx > dy) { + error = dy * 2 - dx; + for(i=0; i<=dx; i++) { + PUTPIXEL(fbptr); + if(error >= 0) { + error -= dx * 2; + fbptr += y_inc; +#ifdef ALT_LCLIP + y0 += y0inc; +#endif + } + error += dy * 2; + fbptr += x_inc; +#ifdef ALT_LCLIP + x0 += x_inc; +#endif + } + } else { + error = dx * 2 - dy; + for(i=0; i<=dy; i++) { + PUTPIXEL(fbptr); + if(error >= 0) { + error -= dy * 2; + fbptr += x_inc; +#ifdef ALT_LCLIP + x0 += x_inc; +#endif + } + error += dx * 2; + fbptr += y_inc; +#ifdef ALT_LCLIP + y0 += y0inc; +#endif + } + } +} + diff --git a/src/polyfill.h b/src/polyfill.h new file mode 100644 index 0000000..88166cf --- /dev/null +++ b/src/polyfill.h @@ -0,0 +1,33 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef POLYFILL_H_ +#define POLYFILL_H_ + +#include + +struct pvertex { + int32_t x, y; +}; + +void polyfill_framebuffer(unsigned char *fb, int width, int height); +void polyfill_flat(struct pvertex *v, int vnum, unsigned char col); + +int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax); +void draw_line(int x0, int y0, int x1, int y1, unsigned short color); + +#endif /* POLYFILL_H_ */ diff --git a/src/sprite.c b/src/sprite.c new file mode 100644 index 0000000..c77ae90 --- /dev/null +++ b/src/sprite.c @@ -0,0 +1,77 @@ +#include "sprite.h" +#include "gbaregs.h" + + +void spr_setup(int xtiles, int ytiles, unsigned char *pixels, unsigned char *cmap) +{ + int i, j, num_tiles; + uint16_t *cptr, *src, *dst; + + num_tiles = xtiles * ytiles; + dst = (uint16_t*)VRAM_LFB_OBJ_ADDR; + src = (uint16_t*)pixels; + for(i=0; i> 3; + unsigned char g = *cmap++ >> 3; + unsigned char b = *cmap++ >> 3; + *cptr++ = r | ((uint16_t)g << 5) | ((uint16_t)b << 10); + } +} + +void spr_clear(void) +{ + int i; + + for(i=0; i<128; i++) { + spr_oam_clear(0, i); + } +} + +void spr_oam(uint16_t *oam, int idx, int spr, int x, int y, unsigned int flags) +{ + if(!oam) oam = (uint16_t*)OAM_ADDR; + + oam += idx << 2; + + oam[0] = (y & 0xff) | (flags & 0xff00); + oam[1] = (x & 0x1ff) | ((flags >> 8) & 0xfe00); + oam[2] = (spr & 0x3ff) | ((flags & 3) << 10); +} + +void spr_spr_oam(uint16_t *oam, int idx, struct sprite *spr) +{ + int i; + struct hwsprite *s; + + s = spr->hwspr; + for(i=0; inum_hwspr; i++) { + spr_oam(oam, idx, s->id, spr->x + s->x, spr->y + s->y, s->flags); + s++; + } +} + +void spr_transform(uint16_t *oam, int idx, int16_t *mat) +{ + if(!oam) oam = (uint16_t*)OAM_ADDR; + + oam += (idx << 4) + 3; + + oam[0] = *mat++; + oam[4] = *mat++; + oam[8] = *mat++; + oam[12] = *mat; +} diff --git a/src/sprite.h b/src/sprite.h new file mode 100644 index 0000000..27d16ff --- /dev/null +++ b/src/sprite.h @@ -0,0 +1,51 @@ +#ifndef SPRITE_H_ +#define SPRITE_H_ + +#include + +enum { + SPR_ROTSCL = 0x0100, + SPR_DBLSZ = 0x0200, + SPR_BLEND = 0x0400, + SPR_OBJWIN = 0x0800, + SPR_MOSAIC = 0x1000, + SPR_256COL = 0x2000, + SPR_HRECT = 0x4000, + SPR_VRECT = 0x8000, + + SPR_HFLIP = 0x100000, + SPR_VFLIP = 0x200000, + SPR_SZ16 = 0x400000, + SPR_SZ32 = 0x800000, + SPR_SZ64 = 0xc00000 +}; +#define SPR_SZ8 0 +#define SPR_ROTSCL_SEL(x) ((unsigned int)(x) << 17) +#define SPR_PRIO(x) ((unsigned int)(x) & 3) + + +struct hwsprite { + short id; + short width, height; + short x, y; + unsigned int flags; +}; + +struct sprite { + short x, y; + struct hwsprite hwspr[8]; + short num_hwspr; +}; + +void spr_setup(int xtiles, int ytiles, unsigned char *pixels, unsigned char *cmap); +void spr_clear(void); + +#define spr_oam_clear(oam, idx) spr_oam(oam, idx, 0, 0, 160, 0) +void spr_oam(uint16_t *oam, int idx, int spr, int x, int y, unsigned int flags); +void spr_spr_oam(uint16_t *oam, int idx, struct sprite *spr); + +/* idx is the rotation/scale parameter index (0-31), not the sprite index */ +void spr_transform(uint16_t *oam, int idx, int16_t *mat); + + +#endif /* SPRITE_H_ */ diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..f4b0c7a --- /dev/null +++ b/src/timer.c @@ -0,0 +1,55 @@ +#include "intr.h" +#include "timer.h" + +#define F_CLK 16780000 +/* clock is 16.78MHz + * - no prescale: 59.595ns + * - prescale 64: 3.814us + * - prescale 256: 15.256us + * - prescale 1024: 61.025us + */ + +static void timer_intr(void); + +void init_timer(int tm, unsigned long rate_hz, void (*intr)(void)) +{ + static const unsigned long clk[] = {F_CLK, F_CLK / 64, F_CLK / 256, F_CLK / 1024}; + unsigned long count; + int pscl = 0; + + do { + count = clk[pscl] / rate_hz; + } while(count >= 65536 && ++pscl < 4); + + if(pscl >= 4) return; /* impossible rate */ + + REG_TMCNT_H(tm) = 0; + REG_TMCNT_L(tm) = 65536 - count; + if(intr) { + interrupt(INTR_TIMER0 + tm, intr); + unmask(INTR_TIMER0 + tm); + REG_TMCNT_H(tm) = TMCNT_IE; + } + REG_TMCNT_H(tm) |= TMCNT_EN | pscl; +} + +void reset_msec_timer(void) +{ + REG_TM0CNT_H &= ~TMCNT_EN; + interrupt(INTR_TIMER0, timer_intr); + timer_msec = 0; + REG_TM0CNT_L = 65535 - 16779; + REG_TM0CNT_H |= TMCNT_IE | TMCNT_EN; + unmask(INTR_TIMER0); +} + +void delay(unsigned long ms) +{ + unsigned long end = timer_msec + ms; + while(timer_msec < end); +} + +static void timer_intr(void) +{ + timer_msec++; +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..3daed47 --- /dev/null +++ b/src/timer.h @@ -0,0 +1,32 @@ +#ifndef TIMER_H_ +#define TIMER_H_ + +#include "gbaregs.h" + +#define enable_timer(x) \ + do { REG_TMCNT_H(x) |= TMCNT_EN; } while(0) + +#define disable_timer(x) \ + do { REG_TMCNT_H(x) &= ~TMCNT_EN; } while(0) + +volatile unsigned long timer_msec; + +void init_timer(int tm, unsigned long rate_hz, void (*intr)(void)); + +void reset_msec_timer(void); + +void delay(unsigned long ms); + +#ifdef __thumb__ +#define udelay(x) asm volatile ( \ + "0: sub %0, %0, #1\n\t" \ + "bne 0b\n\t" \ + :: "r"(x) : "cc") +#else +#define udelay(x) asm volatile ( \ + "0: subs %0, %0, #1\n\t" \ + "bne 0b\n\t" \ + :: "r"(x) : "cc") +#endif + +#endif /* TIMER_H_ */ diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..9bba42f --- /dev/null +++ b/src/util.c @@ -0,0 +1,25 @@ +#include "util.h" +#include "debug.h" + +extern char __iheap_start; +static char *top = &__iheap_start; + +int iwram_brk(void *addr) +{ + if((char*)addr < &__iheap_start) { + addr = &__iheap_start; + } + if(addr > get_sp()) { + /*return -1;*/ + panic(get_pc(), "iwram_brk (%p) >= sp", addr); + } + top = addr; + return 0; +} + +void *iwram_sbrk(intptr_t delta) +{ + void *prev = top; + iwram_brk(top + delta); + return prev; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..789e63e --- /dev/null +++ b/src/util.h @@ -0,0 +1,36 @@ +#ifndef UTIL_H_ +#define UTIL_H_ + +#include + +#define wait_vblank() \ + do { \ + while(REG_DISPSTAT & DISPSTAT_VBLANK); \ + while(!(REG_DISPSTAT & DISPSTAT_VBLANK)); \ + } while(0) + +#define present(x) \ + do { \ + REG_DISPCNT = DISPCNT_BG2 | DISPCNT_OBJ | 4 | ((x) << 4); \ + } while(0) + + +#define set_bg_color(idx, r, g, b) \ + do { \ + ((uint16_t*)CRAM_BG_ADDR)[idx] = (uint16_t)(r) | ((uint16_t)(g) << 5) | ((uint16_t)(b) << 10); \ + } while(0) + +extern int16_t sinlut[]; + +#define SIN(x) sinlut[(x) & 0xff] +#define COS(x) sinlut[((x) + 64) & 0xff] + +int iwram_brk(void *addr); +void *iwram_sbrk(intptr_t delta); + +void fillblock_16byte(void *dest, uint32_t val, int count); + +void *get_pc(void); +void *get_sp(void); + +#endif /* UTIL_H_ */ diff --git a/src/xgl.c b/src/xgl.c new file mode 100644 index 0000000..deccdea --- /dev/null +++ b/src/xgl.c @@ -0,0 +1,294 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include +#include "xgl.h" +#include "polyfill.h" +#include "debug.h" + +#define MAT_STACK_SIZE 4 + +static int vp[4]; +static int32_t mat[MAT_STACK_SIZE][16]; +static int mtop; +static unsigned int opt; +static int32_t ldir[3]; + +static void draw_ptlines(int prim, const struct xvertex *varr, int vcount); + + +void xgl_init(void) +{ + xgl_viewport(0, 0, 240, 160); + xgl_load_identity(); + + ldir[0] = ldir[1] = 0; + ldir[2] = -0x100; +} + +void xgl_enable(unsigned int o) +{ + opt |= o; +} + +void xgl_disable(unsigned int o) +{ + opt &= ~o; +} + +void xgl_viewport(int x, int y, int w, int h) +{ + vp[0] = x; + vp[1] = y; + vp[2] = w; + vp[3] = h; +} + +void xgl_push_matrix(void) +{ + int prev; + + if(mtop >= MAT_STACK_SIZE - 1) return; + + prev = mtop++; + memcpy(mat[mtop], mat[prev], sizeof mat[0]); +} + +void xgl_pop_matrix(void) +{ + if(mtop > 0) mtop--; +} + +static int32_t id[] = { + 0x10000, 0, 0, 0, + 0, 0x10000, 0, 0, + 0, 0, 0x10000, 0, + 0, 0, 0, 0x10000 +}; + +void xgl_load_identity(void) +{ + memcpy(mat[mtop], id, sizeof mat[0]); +} + +void xgl_load_matrix(const int32_t *m) +{ + memcpy(mat[mtop], m, sizeof mat[0]); +} + +void xgl_get_matrix(int32_t *m) +{ + memcpy(m, mat[mtop], sizeof mat[0]); +} + +#define M(i,j) (((i) << 2) + (j)) +#define XMUL(a, b) (((a) >> 8) * ((b) >> 8)) +void xgl_mult_matrix(const int32_t *m2) +{ + int i, j; + int32_t m1[16]; + int32_t *dest = mat[mtop]; + + memcpy(m1, dest, sizeof m1); + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + *dest++ = XMUL(m1[M(0, j)], m2[M(i, 0)]) + + XMUL(m1[M(1, j)], m2[M(i, 1)]) + + XMUL(m1[M(2, j)], m2[M(i, 2)]) + + XMUL(m1[M(3, j)], m2[M(i, 3)]); + } + } +} + +#define XSIN(x) (int32_t)(sin(x / 65536.0f) * 65536.0f) +#define XCOS(x) (int32_t)(cos(x / 65536.0f) * 65536.0f) + +void xgl_translate(int32_t x, int32_t y, int32_t z) +{ + int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000}; + m[12] = x; + m[13] = y; + m[14] = z; + xgl_mult_matrix(m); +} + +void xgl_rotate_x(int32_t angle) +{ + int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000}; + int32_t sa = XSIN(angle); + int32_t ca = XCOS(angle); + m[5] = ca; + m[6] = sa; + m[9] = -sa; + m[10] = ca; + xgl_mult_matrix(m); +} + +void xgl_rotate_y(int32_t angle) +{ + int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000}; + int32_t sa = XSIN(angle); + int32_t ca = XCOS(angle); + m[0] = ca; + m[2] = -sa; + m[8] = sa; + m[10] = ca; + xgl_mult_matrix(m); +} + +void xgl_rotate_z(int32_t angle) +{ + int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000}; + int32_t sa = XSIN(angle); + int32_t ca = XCOS(angle); + m[0] = ca; + m[1] = sa; + m[4] = -sa; + m[5] = ca; + xgl_mult_matrix(m); +} + +void xgl_scale(int32_t x, int32_t y, int32_t z) +{ + int32_t m[16] = {0}; + m[0] = x; + m[5] = y; + m[10] = z; + m[15] = 0x10000; + xgl_mult_matrix(m); +} + +static void xform(struct xvertex *out, const struct xvertex *in, const int32_t *m) +{ + out->x = XMUL(m[0], in->x) + XMUL(m[4], in->y) + XMUL(m[8], in->z) + m[12]; + out->y = XMUL(m[1], in->x) + XMUL(m[5], in->y) + XMUL(m[9], in->z) + m[13]; + out->z = XMUL(m[2], in->x) + XMUL(m[6], in->y) + XMUL(m[10], in->z) + m[14]; +} + +static void xform_norm(struct xvertex *out, const struct xvertex *in, const int32_t *m) +{ + out->nx = XMUL(m[0], in->nx) + XMUL(m[4], in->ny) + XMUL(m[8], in->nz); + out->ny = XMUL(m[1], in->nx) + XMUL(m[5], in->ny) + XMUL(m[9], in->nz); + out->nz = XMUL(m[2], in->nx) + XMUL(m[6], in->ny) + XMUL(m[10], in->nz); +} + +/* d = 1.0 / tan(fov/2) */ +#define PROJ_D 0x20000 + +void xgl_draw(int prim, const struct xvertex *varr, int vcount) +{ + int i, cidx; + struct xvertex xv[4]; + struct pvertex pv[4]; + int32_t ndotl; + + if(prim < 3) { + draw_ptlines(prim, varr, vcount); + return; + } + + while(vcount >= prim) { + cidx = varr->cidx; + + xform(xv, varr, mat[mtop]); + xform_norm(xv, varr, mat[mtop]); + + if(xv->nz > 0) { + /* backface */ + varr += prim; + vcount -= prim; + continue; + } + + if(opt & XGL_LIGHTING) { + ndotl = (xv->nx >> 8) * ldir[0] + (xv->ny >> 8) * ldir[1] + (xv->nz >> 8) * ldir[2]; + if(ndotl < 0) ndotl = 0; + cidx = 128 + (ndotl >> 9); + if(cidx > 255) cidx = 255; + } + + xv->x = (xv->x << 1) / (xv->z >> 8); /* assume aspect: ~2 */ + xv->y = (xv->y << 2) / (xv->z >> 8); /* the shift is * PROJ_D */ + /* projection result is 24.8 */ + /* viewport */ + pv->x = (((xv->x + 0x100) >> 1) * vp[2]) + (vp[0] << 8); + pv->y = (((0x100 - xv->y) >> 1) * vp[3]) + (vp[1] << 8); + varr++; + + for(i=1; i> 8); /* assume aspect: ~2 */ + xv[i].y = (xv[i].y << 2) / (xv[i].z >> 8); /* the shift is * PROJ_D */ + /* projection result is 24.8 */ + /* viewport */ + pv[i].x = (((xv[i].x + 0x100) >> 1) * vp[2]) + (vp[0] << 8); + pv[i].y = (((0x100 - xv[i].y) >> 1) * vp[3]) + (vp[1] << 8); + varr++; + } + vcount -= prim; + + polyfill_flat(pv, prim, cidx); + } +} + +void xgl_transform(const struct xvertex *vin, int *x, int *y) +{ + struct xvertex v; + xform(&v, vin, mat[mtop]); + + v.x = (v.x << 1) / (v.z >> 8); /* assume aspect: ~2 */ + v.y = (v.y << 2) / (v.z >> 8); /* the shift is * PROJ_D */ + /* projection result is 24.8 */ + /* viewport */ + *x = ((((v.x + 0x100) >> 1) * vp[2]) >> 8) + vp[0]; + *y = ((((0x100 - v.y) >> 1) * vp[3]) >> 8) + vp[1]; +} + +static void draw_ptlines(int prim, const struct xvertex *varr, int vcount) +{ + int i; + struct xvertex xv[2]; + + while(vcount >= prim) { + for(i=0; i> 8); /* assume aspect: ~2 */ + xv[i].y = (xv[i].y << 2) / (xv[i].z >> 8); /* the shift is * PROJ_D */ + /* projection result is 24.8 */ + /* viewport */ + xv[i].x = ((((xv[i].x + 0x100) >> 1) * vp[2]) >> 8) + vp[0]; + xv[i].y = ((((0x100 - xv[i].y) >> 1) * vp[3]) >> 8) + vp[1]; + varr++; + } + vcount -= prim; + + /* line clipping */ +#ifndef ALT_LCLIP + clip_line((int*)&xv[0].x, (int*)&xv[0].y, (int*)&xv[1].x, (int*)&xv[1].y, vp[0], vp[1], vp[2] - 1, vp[3] - 1); +#endif + draw_line(xv[0].x, xv[0].y, xv[1].x, xv[1].y, varr[-2].cidx); + } +} + +void xgl_xyzzy(void) +{ + mat[mtop][12] = mat[mtop][13] = 0; +} diff --git a/src/xgl.h b/src/xgl.h new file mode 100644 index 0000000..eba42b5 --- /dev/null +++ b/src/xgl.h @@ -0,0 +1,68 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef XGL_H_ +#define XGL_H_ + +#define X_PI 0x3243f +#define X_2PI 0x6487f +#define X_HPI 0x19220 +#define X_QPI 0xc910 + +enum { + XGL_LIGHTING = 1, + XGL_DEPTH_TEST = 2, +}; + +enum { + XGL_LINES = 2, + XGL_TRIANGLES = 3, + XGL_QUADS = 4 +}; + +struct xvertex { + int32_t x, y, z; + int32_t nx, ny, nz; + unsigned char cidx; +}; + +void xgl_init(void); + +void xgl_enable(unsigned int opt); +void xgl_disable(unsigned int opt); + +void xgl_viewport(int x, int y, int w, int h); + +void xgl_push_matrix(void); +void xgl_pop_matrix(void); +void xgl_load_identity(void); +void xgl_load_matrix(const int32_t *m); +void xgl_get_matrix(int32_t *m); +void xgl_mult_matrix(const int32_t *m); + +void xgl_translate(int32_t x, int32_t y, int32_t z); +void xgl_rotate_x(int32_t angle); +void xgl_rotate_y(int32_t angle); +void xgl_rotate_z(int32_t angle); +void xgl_scale(int32_t x, int32_t y, int32_t z); + +void xgl_draw(int prim, const struct xvertex *varr, int vcount); +void xgl_transform(const struct xvertex *vin, int *x, int *y); + +void xgl_xyzzy(void); + +#endif /* XGL_H_ */ diff --git a/tools/lutgen.c b/tools/lutgen.c new file mode 100644 index 0000000..70d7641 --- /dev/null +++ b/tools/lutgen.c @@ -0,0 +1,16 @@ +#include +#include + +int main(void) +{ + int i; + + puts("\t.data"); + puts("\t.globl sinlut"); + puts("sinlut:"); + for(i=0; i<256; i++) { + float x = sin((float)i / 128.0f * M_PI); + printf("\t.short %d\n", (int)(x * 256.0f)); + } + return 0; +} -- 1.7.10.4