/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Björn Stenberg * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #include #include #include #include #include "debug.h" #include "i2c.h" #include "lang.h" #include "keyboard.h" #include "buffer.h" #include "backlight.h" #include "sound_menu.h" #include "mp3data.h" #include "powermgmt.h" #include "splash.h" #include "logf.h" #if CONFIG_CHARGING #include "power.h" #endif #ifdef HAVE_LCD_BITMAP #include "scrollbar.h" #include "peakmeter.h" #include "bmp.h" #include "bidi.h" #endif #ifdef SIMULATOR static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE]; void *sim_plugin_load(char *plugin, void **pd); void sim_plugin_close(void *pd); void sim_lcd_ex_init(int shades, unsigned long (*getpixel)(int, int)); void sim_lcd_ex_update_rect(int x, int y, int width, int height); #else #define sim_plugin_close(x) extern unsigned char pluginbuf[]; #include "bitswap.h" #endif /* for actual plugins only, not for codecs */ static bool plugin_loaded = false; static int plugin_size = 0; static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */ static char current_plugin[MAX_PATH]; static const struct plugin_api rockbox_api = { /* lcd */ lcd_set_contrast, lcd_update, lcd_clear_display, lcd_setmargins, lcd_getstringsize, lcd_putsxy, lcd_puts, lcd_puts_scroll, lcd_stop_scroll, #ifdef HAVE_LCD_CHARCELLS lcd_define_pattern, lcd_get_locked_pattern, lcd_unlock_pattern, lcd_putc, lcd_put_cursor, lcd_remove_cursor, PREFIX(lcd_icon), lcd_double_height, #else lcd_set_drawmode, lcd_get_drawmode, lcd_setfont, lcd_drawpixel, lcd_drawline, lcd_hline, lcd_vline, lcd_drawrect, lcd_fillrect, lcd_mono_bitmap_part, lcd_mono_bitmap, #if LCD_DEPTH > 1 lcd_set_foreground, lcd_get_foreground, lcd_set_background, lcd_get_background, lcd_bitmap_part, lcd_bitmap, lcd_set_backdrop, #endif #if LCD_DEPTH == 16 lcd_bitmap_transparent_part, lcd_bitmap_transparent, #endif bidi_l2v, font_get_bits, font_load, lcd_puts_style, lcd_puts_scroll_style, &lcd_framebuffer[0][0], lcd_blit, lcd_update_rect, gui_scrollbar_draw, font_get, font_getstringsize, font_get_width, #endif backlight_on, backlight_off, backlight_set_timeout, gui_syncsplash, #ifdef HAVE_REMOTE_LCD /* remote lcd */ lcd_remote_set_contrast, lcd_remote_clear_display, lcd_remote_puts, lcd_remote_puts_scroll, lcd_remote_stop_scroll, lcd_remote_set_drawmode, lcd_remote_get_drawmode, lcd_remote_setfont, lcd_remote_getstringsize, lcd_remote_drawpixel, lcd_remote_drawline, lcd_remote_hline, lcd_remote_vline, lcd_remote_drawrect, lcd_remote_fillrect, lcd_remote_mono_bitmap_part, lcd_remote_mono_bitmap, lcd_remote_putsxy, lcd_remote_puts_style, lcd_remote_puts_scroll_style, &lcd_remote_framebuffer[0][0], lcd_remote_update, lcd_remote_update_rect, remote_backlight_on, remote_backlight_off, #endif #if NB_SCREENS == 2 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]}, #else {&screens[SCREEN_MAIN]}, #endif #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) lcd_remote_set_foreground, lcd_remote_get_foreground, lcd_remote_set_background, lcd_remote_get_background, lcd_remote_bitmap_part, lcd_remote_bitmap, #endif #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) lcd_yuv_blit, #endif /* list */ gui_synclist_init, gui_synclist_set_nb_items, gui_synclist_set_icon_callback, gui_synclist_get_nb_items, gui_synclist_get_sel_pos, gui_synclist_draw, gui_synclist_select_item, gui_synclist_add_item, gui_synclist_del_item, gui_synclist_limit_scroll, gui_synclist_flash, gui_synclist_do_button, gui_synclist_set_title, /* button */ button_get, button_get_w_tmo, button_status, button_clear_queue, #ifdef HAS_BUTTON_HOLD button_hold, #endif /* file */ (open_func)PREFIX(open), close, (read_func)read, PREFIX(lseek), (creat_func)PREFIX(creat), (write_func)write, PREFIX(remove), PREFIX(rename), PREFIX(ftruncate), PREFIX(filesize), fdprintf, read_line, settings_parseline, #ifndef SIMULATOR ata_sleep, ata_disk_is_active, #endif ata_spindown, reload_directory, /* dir */ PREFIX(opendir), PREFIX(closedir), PREFIX(readdir), PREFIX(mkdir), PREFIX(rmdir), /* dir, cached */ #ifdef HAVE_DIRCACHE opendir_cached, readdir_cached, closedir_cached, #endif /* kernel/ system */ PREFIX(sleep), yield, ¤t_tick, default_event_handler, default_event_handler_ex, create_thread, remove_thread, reset_poweroff_timer, #ifndef SIMULATOR system_memory_guard, &cpu_frequency, #ifdef HAVE_ADJUSTABLE_CPU_FREQ #ifdef CPU_BOOST_LOGGING cpu_boost_, #else cpu_boost, #endif #endif timer_register, timer_unregister, timer_set_period, #endif queue_init, queue_delete, queue_post, queue_wait_w_tmo, usb_acknowledge, #ifdef RB_PROFILE profile_thread, profstop, profile_func_enter, profile_func_exit, #endif #ifdef SIMULATOR /* special simulator hooks */ #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH < 8 sim_lcd_ex_init, sim_lcd_ex_update_rect, #endif #endif /* strings and memory */ snprintf, vsnprintf, strcpy, strncpy, strlen, strrchr, strcmp, strncmp, strcasecmp, strncasecmp, memset, memcpy, memmove, _ctype_, atoi, strchr, strcat, memchr, memcmp, strcasestr, strtok_r, /* unicode stuff */ utf8decode, iso_decode, utf16LEdecode, utf16BEdecode, utf8encode, utf8length, utf8seek, /* sound */ sound_set, set_sound, sound_min, sound_max, #ifndef SIMULATOR mp3_play_data, mp3_play_pause, mp3_play_stop, mp3_is_playing, #if CONFIG_CODEC != SWCODEC bitswap, #endif #endif #if CONFIG_CODEC == SWCODEC pcm_play_data, pcm_play_stop, pcm_set_frequency, pcm_is_playing, pcm_play_pause, #endif #if CONFIG_CODEC == SWCODEC pcm_calculate_peaks, #endif /* playback control */ PREFIX(audio_play), audio_stop, audio_pause, audio_resume, audio_next, audio_prev, audio_ff_rewind, audio_next_track, playlist_amount, audio_status, audio_has_changed_track, audio_current_track, audio_flush_and_reload_tracks, audio_get_file_pos, #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC) mpeg_get_last_header, #endif #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) || \ (CONFIG_CODEC == SWCODEC) sound_set_pitch, #endif #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC) /* MAS communication */ mas_readmem, mas_writemem, mas_readreg, mas_writereg, #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) mas_codec_writereg, mas_codec_readreg, i2c_begin, i2c_end, i2c_write, #endif #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */ /* menu */ do_menu, /* OLD API - dont use unless you have to */ menu_init, menu_exit, menu_show, menu_run, menu_count, set_option, set_int, set_bool, /* action handling */ get_custom_action, get_action, action_signalscreenchange, action_userabort, /* power */ battery_level, battery_level_safe, battery_time, #ifndef SIMULATOR battery_voltage, #endif #if CONFIG_CHARGING charger_inserted, # if CONFIG_CHARGING == CHARGING_MONITOR charging_state, # endif #endif #ifdef HAVE_USB_POWER usb_powered, #endif /* misc */ srand, rand, (qsort_func)qsort, kbd_input, get_time, set_time, plugin_get_buffer, plugin_get_audio_buffer, plugin_tsr, #if defined(DEBUG) || defined(SIMULATOR) debugf, #endif #ifdef ROCKBOX_HAS_LOGF _logf, #endif &global_settings, mp3info, count_mp3_frames, create_xing_header, find_next_frame, #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) peak_meter_scale_value, peak_meter_set_use_dbfs, peak_meter_get_use_dbfs, #endif #ifdef HAVE_LCD_BITMAP read_bmp_file, screen_dump_set_hook, #endif show_logo, tree_get_context, #ifdef HAVE_WHEEL_POSITION wheel_status, wheel_send_events, #endif #if LCD_DEPTH > 1 lcd_get_backdrop, #endif /* new stuff at the end, sort into place next time the API gets incompatible */ /* Keep these at the bottom till fully proven */ #if CONFIG_CODEC == SWCODEC &audio_master_sampr_list[0], &hw_freq_sampr[0], #ifndef SIMULATOR pcm_apply_settings, #endif #ifdef HAVE_RECORDING &rec_freq_sampr[0], #ifndef SIMULATOR pcm_init_recording, pcm_close_recording, pcm_record_data, pcm_stop_recording, pcm_calculate_rec_peaks, audio_set_recording_gain, audio_set_output_source, rec_set_source, #endif #endif /* HAVE_RECORDING */ #endif /* CONFIG_CODEC == SWCODEC */ #ifdef IRAM_STEAL plugin_iram_init, #endif #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(SIMULATOR) sound_default, pcm_record_more, #endif #ifdef IRIVER_H100_SERIES /* Routines for the iriver_flash -plugin. */ detect_original_firmware, detect_flashed_ramimage, detect_flashed_romimage, #endif playlist_resume, playlist_start, &global_status, #if CONFIG_CODEC == SWCODEC pcm_get_bytes_waiting, #endif }; int plugin_load(const char* plugin, void* parameter) { int rc; struct plugin_header *hdr; const char *p = strrchr(plugin,'/'); #ifdef SIMULATOR void *pd; #else int fd; ssize_t readsize; #endif #ifdef HAVE_LCD_BITMAP int xm, ym; #endif #ifdef HAVE_REMOTE_LCD int rxm, rym; #endif #if LCD_DEPTH > 1 fb_data* old_backdrop; #endif if (!p) p = plugin; action_signalscreenchange(); if (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */ { if (pfn_tsr_exit(!strcmp(current_plugin,p)) == false ) { /* not allowing another plugin to load */ return PLUGIN_OK; } pfn_tsr_exit = NULL; plugin_loaded = false; } gui_syncsplash(0, str(LANG_WAIT)); strcpy(current_plugin,p); #ifdef SIMULATOR hdr = sim_plugin_load((char *)plugin, &pd); if (pd == NULL) { gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin); return -1; } if (hdr == NULL || hdr->magic != PLUGIN_MAGIC || hdr->target_id != TARGET_ID) { sim_plugin_close(pd); gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL)); return -1; } if (hdr->api_version > PLUGIN_API_VERSION || hdr->api_version < PLUGIN_MIN_API_VERSION) { sim_plugin_close(pd); gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION)); return -1; } #else fd = open(plugin, O_RDONLY); if (fd < 0) { gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin); return fd; } readsize = read(fd, pluginbuf, PLUGIN_BUFFER_SIZE); close(fd); if (readsize < 0) { gui_syncsplash(HZ*2, str(LANG_READ_FAILED), plugin); return -1; } hdr = (struct plugin_header *)pluginbuf; if ((unsigned)readsize <= sizeof(struct plugin_header) || hdr->magic != PLUGIN_MAGIC || hdr->target_id != TARGET_ID || hdr->load_addr != pluginbuf || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE) { gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL)); return -1; } if (hdr->api_version > PLUGIN_API_VERSION || hdr->api_version < PLUGIN_MIN_API_VERSION) { gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION)); return -1; } plugin_size = hdr->end_addr - pluginbuf; /* zero out bss area only, above guards end of pluginbuf */ memset(pluginbuf + readsize, 0, plugin_size - readsize); #endif plugin_loaded = true; #ifdef HAVE_LCD_BITMAP xm = lcd_getxmargin(); ym = lcd_getymargin(); lcd_setmargins(0,0); #if LCD_DEPTH > 1 old_backdrop = lcd_get_backdrop(); #endif lcd_clear_display(); lcd_update(); #else /* !HAVE_LCD_BITMAP */ lcd_clear_display(); #endif #ifdef HAVE_REMOTE_LCD rxm = lcd_remote_getxmargin(); rym = lcd_remote_getymargin(); lcd_remote_setmargins(0, 0); lcd_remote_clear_display(); lcd_remote_update(); #endif invalidate_icache(); rc = hdr->entry_point((struct plugin_api*) &rockbox_api, parameter); /* explicitly casting the pointer here to avoid touching every plugin. */ action_signalscreenchange(); button_clear_queue(); #ifdef HAVE_LCD_BITMAP #if LCD_DEPTH > 1 lcd_set_backdrop(old_backdrop); #ifdef HAVE_LCD_COLOR lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color, global_settings.bg_color); #else lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG); #endif #else /* LCD_DEPTH == 1 */ lcd_set_drawmode(DRMODE_SOLID); #endif /* LCD_DEPTH */ /* restore margins */ lcd_setmargins(xm,ym); lcd_clear_display(); lcd_update(); #endif /* HAVE_LCD_BITMAP */ #ifdef HAVE_REMOTE_LCD #if LCD_REMOTE_DEPTH > 1 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG, LCD_REMOTE_DEFAULT_BG); #else lcd_remote_set_drawmode(DRMODE_SOLID); #endif lcd_remote_setmargins(rxm, rym); lcd_remote_clear_display(); lcd_remote_update(); #endif if (pfn_tsr_exit == NULL) plugin_loaded = false; sim_plugin_close(pd); switch (rc) { case PLUGIN_OK: break; case PLUGIN_USB_CONNECTED: return PLUGIN_USB_CONNECTED; default: gui_syncsplash(HZ*2, str(LANG_PLUGIN_ERROR)); break; } return PLUGIN_OK; } /* Returns a pointer to the portion of the plugin buffer that is not already being used. If no plugin is loaded, returns the entire plugin buffer */ void* plugin_get_buffer(int* buffer_size) { int buffer_pos; if (plugin_loaded) { if (plugin_size >= PLUGIN_BUFFER_SIZE) return NULL; *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size; buffer_pos = plugin_size; } else { *buffer_size = PLUGIN_BUFFER_SIZE; buffer_pos = 0; } return &pluginbuf[buffer_pos]; } /* Returns a pointer to the mp3 buffer. Playback gets stopped, to avoid conflicts. Talk buffer is stolen as well. */ void* plugin_get_audio_buffer(int* buffer_size) { #if CONFIG_CODEC == SWCODEC return audio_get_buffer(true, (size_t *)buffer_size); #else audio_stop(); talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ *buffer_size = audiobufend - audiobuf; return audiobuf; #endif } #ifdef IRAM_STEAL /* Initializes plugin IRAM */ void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size, char *iedata, size_t iedata_size) { audio_iram_steal(); memcpy(iramstart, iramcopy, iram_size); memset(iedata, 0, iedata_size); memset(iramcopy, 0, iram_size); } #endif /* IRAM_STEAL */ /* The plugin wants to stay resident after leaving its main function, e.g. runs from timer or own thread. The callback is registered to later instruct it to free its resources before a new plugin gets loaded. */ void plugin_tsr(bool (*exit_callback)(bool)) { pfn_tsr_exit = exit_callback; /* remember the callback for later */ } href='#n404'>404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2006 by David Bryant
 *
 * 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 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

/* This is an assembly optimized version of the following WavPack function:
 *
 * void decorr_stereo_pass_cont_arml (struct decorr_pass *dpp,
 *                                    long *buffer, long sample_count);
 *
 * It performs a single pass of stereo decorrelation on the provided buffer.
 * Note that this version of the function requires that the 8 previous stereo
 * samples are visible and correct. In other words, it ignores the "samples_*"
 * fields in the decorr_pass structure and gets the history data directly
 * from the buffer. It does, however, return the appropriate history samples
 * to the decorr_pass structure before returning.
 *
 * This is written to work on a ARM7TDMI processor. This version uses the
 * 64-bit multiply-accumulate instruction and so can be used with all
 * WavPack files. However, for optimum performance with 16-bit WavPack
 * files, there is a faster version that only uses the 32-bit MLA
 * instruction.
 */

        .text
        .align
        .global         decorr_stereo_pass_cont_arml

/*
 * on entry:
 *
 * r0 = struct decorr_pass *dpp
 * r1 = long *buffer
 * r2 = long sample_count
 */

decorr_stereo_pass_cont_arml:

        stmfd   sp!, {r4 - r8, r10, r11, lr}
        mov     r5, r0                  @ r5 = dpp
        mov     r11, #512               @ r11 = 512 for rounding
        ldrsh   r6, [r0, #2]            @ r6 = dpp->delta
        ldrsh   r4, [r0, #4]            @ r4 = dpp->weight_A
        ldrsh   r0, [r0, #6]            @ r0 = dpp->weight_B
        cmp     r2, #0                  @ exit if no samples to process
        beq     common_exit

        mov     r0, r0, asl #18         @ for 64-bit math we use weights << 18
        mov     r4, r4, asl #18
        mov     r6, r6, asl #18
        add     r7, r1, r2, asl #3      @ r7 = buffer ending position
        ldrsh   r2, [r5, #0]            @ r2 = dpp->term
        cmp     r2, #0
        blt     minus_term

        ldr     lr, [r1, #-16]          @ load 2 sample history from buffer
        ldr     r10, [r1, #-12]         @  for terms 2, 17, and 18
        ldr     r8, [r1, #-8]
        ldr     r3, [r1, #-4]

        cmp     r2, #18
        beq     term_18_loop
        mov     lr, lr, asl #4
        mov     r10, r10, asl #4
        cmp     r2, #2
        beq     term_2_loop
        cmp     r2, #17
        beq     term_17_loop
        b       term_default_loop

minus_term:
        mov     r10, #(1024 << 18)      @ r10 = -1024 << 18 for weight clipping
        rsb     r10, r10, #0            @  (only used for negative terms)
        cmn     r2, #1
        beq     term_minus_1
        cmn     r2, #2
        beq     term_minus_2
        cmn     r2, #3
        beq     term_minus_3
        b       common_exit

/*
 ******************************************************************************
 * Loop to handle term = 17 condition
 *
 * r0 = dpp->weight_B           r8 = previous left sample
 * r1 = bptr                    r9 = 
 * r2 = current sample          r10 = second previous left sample << 4
 * r3 = previous right sample   r11 = lo accumulator (for rounding)
 * r4 = dpp->weight_A           ip = current decorrelation value
 * r5 = dpp                     sp =
 * r6 = dpp->delta              lr = second previous right sample << 4
 * r7 = eptr                    pc =
 *******************************************************************************
 */

term_17_loop:
        rsbs    ip, lr, r8, asl #5      @ decorr value = (2 * prev) - 2nd prev
        mov     lr, r8, asl #4          @ previous becomes 2nd previous
        ldr     r2, [r1], #4            @ get sample & update pointer
        mov     r11, #0x80000000
        mov     r8, r2
        smlalne r11, r8, r4, ip
        strne   r8, [r1, #-4]           @ if change possible, store sample back
        cmpne   r2, #0
        beq     .L325
        teq     ip, r2                  @ update weight based on signs
        submi   r4, r4, r6
        addpl   r4, r4, r6

.L325:  rsbs    ip, r10, r3, asl #5     @ do same thing for right channel
        mov     r10, r3, asl #4
        ldr     r2, [r1], #4
        mov     r11, #0x80000000
        mov     r3, r2
        smlalne r11, r3, r0, ip
        strne   r3, [r1, #-4]
        cmpne   r2, #0
        beq     .L329
        teq     ip, r2
        submi   r0, r0, r6
        addpl   r0, r0, r6

.L329:  cmp     r7, r1                  @ loop back if more samples to do
        bhi     term_17_loop
        mov     lr, lr, asr #4
        mov     r10, r10, asr #4
        b       store_1718              @ common exit for terms 17 & 18

/*
 ******************************************************************************
 * Loop to handle term = 18 condition
 *
 * r0 = dpp->weight_B           r8 = previous left sample
 * r1 = bptr                    r9 = 
 * r2 = current sample          r10 = second previous left sample
 * r3 = previous right sample   r11 = lo accumulator (for rounding)
 * r4 = dpp->weight_A           ip = decorrelation value
 * r5 = dpp                     sp =
 * r6 = dpp->delta              lr = second previous right sample
 * r7 = eptr                    pc =
 *******************************************************************************
 */

term_18_loop:
        rsb     ip, lr, r8              @ decorr value =
        mov     lr, r8                  @  ((3 * prev) - 2nd prev) >> 1
        add     ip, lr, ip, asr #1
        movs    ip, ip, asl #4
        ldr     r2, [r1], #4            @ get sample & update pointer
        mov     r11, #0x80000000
        mov     r8, r2
        smlalne r11, r8, r4, ip
        strne   r8, [r1, #-4]           @ if change possible, store sample back
        cmpne   r2, #0
        beq     .L337
        teq     ip, r2                  @ update weight based on signs
        submi   r4, r4, r6
        addpl   r4, r4, r6

.L337:  rsb     ip, r10, r3             @ do same thing for right channel
        mov     r10, r3
        add     ip, r10, ip, asr #1
        movs    ip, ip, asl #4
        ldr     r2, [r1], #4
        mov     r11, #0x80000000
        mov     r3, r2
        smlalne r11, r3, r0, ip
        strne   r3, [r1, #-4]
        cmpne   r2, #0
        beq     .L341
        teq     ip, r2
        submi   r0, r0, r6
        addpl   r0, r0, r6

.L341:  cmp     r7, r1                  @ loop back if more samples to do
        bhi     term_18_loop

/* common exit for terms 17 & 18 */

store_1718:
        str     r3, [r5, #40]           @ store sample history into struct
        str     r8, [r5, #8]
        str     r10, [r5, #44]
        str     lr, [r5, #12]
        b       common_exit             @ and return

/*
 ******************************************************************************
 * Loop to handle term = 2 condition
 * (note that this case can be handled by the default term handler (1-8), but
 * this special case is faster because it doesn't have to read memory twice)
 *
 * r0 = dpp->weight_B           r8 = previous left sample
 * r1 = bptr                    r9 = 
 * r2 = current sample          r10 = second previous left sample << 4
 * r3 = previous right sample   r11 = lo accumulator (for rounding)
 * r4 = dpp->weight_A           ip = decorrelation value
 * r5 = dpp                     sp =
 * r6 = dpp->delta              lr = second previous right sample << 4
 * r7 = eptr                    pc =
 *******************************************************************************
 */

term_2_loop:
        movs    ip, lr                  @ get decorrelation value & test
        ldr     r2, [r1], #4            @ get sample & update pointer
        mov     lr, r8, asl #4          @ previous becomes 2nd previous
        mov     r11, #0x80000000
        mov     r8, r2
        smlalne r11, r8, r4, ip
        strne   r8, [r1, #-4]           @ if change possible, store sample back
        cmpne   r2, #0
        beq     .L225
        teq     ip, r2                  @ update weight based on signs
        submi   r4, r4, r6
        addpl   r4, r4, r6

.L225:  movs    ip, r10                 @ do same thing for right channel
        ldr     r2, [r1], #4
        mov     r10, r3, asl #4
        mov     r11, #0x80000000
        mov     r3, r2
        smlalne r11, r3, r0, ip
        strne   r3, [r1, #-4]
        cmpne   r2, #0
        beq     .L229
        teq     ip, r2
        submi   r0, r0, r6
        addpl   r0, r0, r6

.L229:  cmp     r7, r1                  @ loop back if more samples to do
        bhi     term_2_loop

        b       default_term_exit       @ this exit updates all dpp->samples

/*
 ******************************************************************************
 * Loop to handle default term condition
 *
 * r0 = dpp->weight_B           r8 = result accumulator
 * r1 = bptr                    r9 = 
 * r2 = dpp->term               r10 =
 * r3 = decorrelation value     r11 = lo accumulator (for rounding)
 * r4 = dpp->weight_A           ip = current sample
 * r5 = dpp                     sp =
 * r6 = dpp->delta              lr =
 * r7 = eptr                    pc =
 *******************************************************************************
 */

term_default_loop:
        ldr     r3, [r1, -r2, asl #3]   @ get decorrelation value based on term
        ldr     ip, [r1], #4            @ get original sample and bump ptr
        movs    r3, r3, asl #4
        mov     r11, #0x80000000
        mov     r8, ip
        smlalne r11, r8, r4, r3
        strne   r8, [r1, #-4]           @ if possibly changed, store updated sample
        cmpne   ip, #0
        beq     .L350
        teq     ip, r3                  @ update weight based on signs
        submi   r4, r4, r6
        addpl   r4, r4, r6

.L350:  ldr     r3, [r1, -r2, asl #3]   @ do the same thing for right channel
        ldr     ip, [r1], #4
        movs    r3, r3, asl #4
        mov     r11, #0x80000000
        mov     r8, ip
        smlalne r11, r8, r0, r3
        strne   r8, [r1, #-4]
        cmpne   ip, #0
        beq     .L354
        teq     ip, r3
        submi   r0, r0, r6
        addpl   r0, r0, r6

.L354:  cmp     r7, r1                  @ loop back if more samples to do
        bhi     term_default_loop

/*
 * This exit is used by terms 1-8 to store the previous 8 samples into the decorr
 * structure (even if they are not all used for the given term)
 */

default_term_exit:
        ldrsh   r3, [r5, #0]
        sub     ip, r3, #1
        mov     lr, #7

.L358:  and     r3, ip, #7
        add     r3, r5, r3, asl #2
        ldr     r2, [r1, #-4]
        str     r2, [r3, #40]
        ldr     r2, [r1, #-8]!
        str     r2, [r3, #8]
        sub     ip, ip, #1
        sub     lr, lr, #1
        cmn     lr, #1
        bne     .L358
        b       common_exit

/*
 ******************************************************************************
 * Loop to handle term = -1 condition
 *
 * r0 = dpp->weight_B           r8 =
 * r1 = bptr                    r9 = 
 * r2 = intermediate result     r10 = -1024 (for clipping)
 * r3 = previous right sample   r11 = lo accumulator (for rounding)
 * r4 = dpp->weight_A           ip = current sample
 * r5 = dpp                     sp =
 * r6 = dpp->delta              lr = updated left sample
 * r7 = eptr                    pc =
 *******************************************************************************
 */

term_minus_1:
        ldr     r3, [r1, #-4]

term_minus_1_loop:
        ldr     ip, [r1], #8            @ for left channel the decorrelation value
        movs    r3, r3, asl #4          @  is the previous right sample (in r3)
        mov     r11, #0x80000000
        mov     lr, ip
        smlalne r11, lr, r4, r3
        strne   lr, [r1, #-8]
        cmpne   ip, #0
        beq     .L361
        teq     ip, r3                  @ update weight based on signs
        submi   r4, r4, r6
        addpl   r4, r4, r6
        cmp     r4, #(1024 << 18)
        movgt   r4, #(1024 << 18)
        cmp     r4, r10
        movlt   r4, r10

.L361:  ldr     r2, [r1, #-4]           @ for right channel the decorrelation value
        movs    lr, lr, asl #4
        mov     r11, #0x80000000
        mov     r3, r2
        smlalne r11, r3, r0, lr
        strne   r3, [r1, #-4]
        cmpne   r2, #0
        beq     .L369
        teq     r2, lr
        submi   r0, r0, r6
        addpl   r0, r0, r6
        cmp     r0, #(1024 << 18)               @ then clip weight to +/-1024
        movgt   r0, #(1024 << 18)
        cmp     r0, r10
        movlt   r0, r10

.L369:  cmp     r7, r1                  @ loop back if more samples to do
        bhi     term_minus_1_loop

        str     r3, [r5, #8]            @ else store right sample and exit
        b       common_exit

/*
 ******************************************************************************
 * Loop to handle term = -2 condition
 * (note that the channels are processed in the reverse order here)
 *
 * r0 = dpp->weight_B           r8 =
 * r1 = bptr                    r9 = 
 * r2 = intermediate result     r10 = -1024 (for clipping)
 * r3 = previous left sample    r11 = lo accumulator (for rounding)
 * r4 = dpp->weight_A           ip = current sample
 * r5 = dpp                     sp =
 * r6 = dpp->delta              lr = updated right sample
 * r7 = eptr                    pc =
 *******************************************************************************
 */

term_minus_2:
        ldr     r3, [r1, #-8]

term_minus_2_loop:
        ldr     ip, [r1, #4]            @ for right channel the decorrelation value
        movs    r3, r3, asl #4          @  is the previous left sample (in r3)
        mov     r11, #0x80000000
        mov     lr, ip
        smlalne r11, lr, r0, r3
        strne   lr, [r1, #4]
        cmpne   ip, #0
        beq     .L380
        teq     ip, r3                  @ update weight based on signs
        submi   r0, r0, r6
        addpl   r0, r0, r6
        cmp     r0, #(1024 << 18)               @ then clip weight to +/-1024
        movgt   r0, #(1024 << 18)
        cmp     r0, r10
        movlt   r0, r10

.L380:  ldr     r2, [r1], #8            @ for left channel the decorrelation value
        movs    lr, lr, asl #4
        mov     r11, #0x80000000
        mov     r3, r2
        smlalne r11, r3, r4, lr
        strne   r3, [r1, #-8]
        cmpne   r2, #0
        beq     .L388
        teq     r2, lr
        submi   r4, r4, r6
        addpl   r4, r4, r6
        cmp     r4, #(1024 << 18)
        movgt   r4, #(1024 << 18)
        cmp     r4, r10
        movlt   r4, r10

.L388:  cmp     r7, r1                  @ loop back if more samples to do
        bhi     term_minus_2_loop

        str     r3, [r5, #40]           @ else store left channel and exit
        b       common_exit

/*
 ******************************************************************************
 * Loop to handle term = -3 condition
 *
 * r0 = dpp->weight_B           r8 = previous left sample
 * r1 = bptr                    r9 = 
 * r2 = current left sample     r10 = -1024 (for clipping)
 * r3 = previous right sample   r11 = lo accumulator (for rounding)
 * r4 = dpp->weight_A           ip = intermediate result
 * r5 = dpp                     sp =
 * r6 = dpp->delta              lr =
 * r7 = eptr                    pc =
 *******************************************************************************
 */

term_minus_3:
        ldr     r3, [r1, #-4]           @ load previous samples
        ldr     r8, [r1, #-8]

term_minus_3_loop:
        ldr     ip, [r1], #4
        movs    r3, r3, asl #4
        mov     r11, #0x80000000
        mov     r2, ip
        smlalne r11, r2, r4, r3
        strne   r2, [r1, #-4]
        cmpne   ip, #0
        beq     .L399
        teq     ip, r3                  @ update weight based on signs
        submi   r4, r4, r6
        addpl   r4, r4, r6
        cmp     r4, #(1024 << 18)       @ then clip weight to +/-1024
        movgt   r4, #(1024 << 18)
        cmp     r4, r10
        movlt   r4, r10

.L399:  movs    ip, r8, asl #4          @ ip = previous left we use now
        mov     r8, r2                  @ r8 = current left we use next time
        ldr     r2, [r1], #4
        mov     r11, #0x80000000
        mov     r3, r2
        smlalne r11, r3, r0, ip
        strne   r3, [r1, #-4]
        cmpne   r2, #0
        beq     .L407
        teq     ip, r2
        submi   r0, r0, r6
        addpl   r0, r0, r6
        cmp     r0, #(1024 << 18)
        movgt   r0, #(1024 << 18)
        cmp     r0, r10
        movlt   r0, r10

.L407:  cmp     r7, r1                  @ loop back if more samples to do
        bhi     term_minus_3_loop

        str     r3, [r5, #8]            @ else store previous samples & exit
        str     r8, [r5, #40]

/*
 * Before finally exiting we must store weights back for next time
 */

common_exit:
        mov     r0, r0, asr #18         @ restore weights to real magnitude
        mov     r4, r4, asr #18
        strh    r4, [r5, #4]
        strh    r0, [r5, #6]
        ldmfd   sp!, {r4 - r8, r10, r11, pc}