/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2000 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * * 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 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * DESCRIPTION: * the automap code * *----------------------------------------------------------------------------- */ #include "doomstat.h" #include "st_stuff.h" #include "r_main.h" #include "p_setup.h" #include "p_maputl.h" #include "w_wad.h" #include "v_video.h" #include "p_spec.h" #include "am_map.h" #include "dstrings.h" #include "d_deh.h" // Ty 03/27/98 - externalizations #include "g_game.h" #include "rockmacros.h" //jff 1/7/98 default automap colors added int mapcolor_back; // map background int mapcolor_grid; // grid lines color int mapcolor_wall; // normal 1s wall color int mapcolor_fchg; // line at floor height change color int mapcolor_cchg; // line at ceiling height change color int mapcolor_clsd; // line at sector with floor=ceiling color int mapcolor_rkey; // red key color int mapcolor_bkey; // blue key color int mapcolor_ykey; // yellow key color int mapcolor_rdor; // red door color (diff from keys to allow option) int mapcolor_bdor; // blue door color (of enabling one but not other ) int mapcolor_ydor; // yellow door color int mapcolor_tele; // teleporter line color int mapcolor_secr; // secret sector boundary color int mapcolor_exit; // jff 4/23/98 add exit line color int mapcolor_unsn; // computer map unseen line color int mapcolor_flat; // line with no floor/ceiling changes int mapcolor_sprt; // general sprite color int mapcolor_item; // item sprite color int mapcolor_frnd; // friendly sprite color int mapcolor_hair; // crosshair color int mapcolor_sngl; // single player arrow color int mapcolor_plyr[4] = { 112, 88, 64, 176 }; // colors for player arrows in multiplayer //jff 3/9/98 add option to not show secret sectors until entered int map_secret_after; //jff 4/3/98 add symbols for "no-color" for disable and "black color" for black #define NC 0 #define BC 247 // drawing stuff #define FB 0 // scale on entry #define INITSCALEMTOF (.2*FRACUNIT) // how much the automap moves window per tic in frame-buffer coordinates // moves 140 pixels in 1 second #define F_PANINC 4 // how much zoom-in per tic // goes to 2x in 1 second #define M_ZOOMIN ((int) (1.02*FRACUNIT)) // how much zoom-out per tic // pulls out to 0.5x in 1 second #define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // translates between frame-buffer and map distances #define FTOM(x) FixedMul(((x)<<16),scale_ftom) #define MTOF(x) (FixedMul((x),scale_mtof)>>16) // translates between frame-buffer and map coordinates #define CXMTOF(x) (f_x + MTOF((x)-m_x)) #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) typedef struct { int x, y; } fpoint_t; typedef struct { fpoint_t a, b; } fline_t; typedef struct { mpoint_t a, b; } mline_t; typedef struct { fixed_t slp, islp; } islope_t; // // The vector graphics for the automap. // A line drawing of the player pointing right, // starting from the middle. // #define R ((8*PLAYERRADIUS)/7) mline_t player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; #undef R #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) #define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { // killough 3/22/98: He's alive, Jim :) { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }, { { -R/10-R/6, R/4}, {-R/10-R/6, -R/4} }, // J { { -R/10-R/6, -R/4}, {-R/10-R/6-R/8, -R/4} }, { { -R/10-R/6-R/8, -R/4}, {-R/10-R/6-R/8, -R/8} }, { { -R/10, R/4}, {-R/10, -R/4}}, // F { { -R/10, R/4}, {-R/10+R/8, R/4}}, { { -R/10+R/4, R/4}, {-R/10+R/4, -R/4}}, // F { { -R/10+R/4, R/4}, {-R/10+R/4+R/8, R/4}}, }; #undef R #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) #define R (FRACUNIT) mline_t triangle_guy[] = { { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)( .867*R), (fixed_t)(-.5*R) } }, { { (fixed_t)( .867*R), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)( R) } }, { { (fixed_t)(0 ), (fixed_t)( R) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } }; #undef R #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) //jff 1/5/98 new symbol for keys on automap #define R (FRACUNIT) mline_t cross_mark[] = { { { -R, 0 }, { R, 0} }, { { 0, -R }, { 0, R } }, }; #undef R #define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t)) //jff 1/5/98 end of new symbol #define R (FRACUNIT) mline_t thintriangle_guy[] = { { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)( R), (fixed_t)( 0) } }, { { (fixed_t)( R), (fixed_t)( 0) }, { (fixed_t)(-.5*R), (fixed_t)( .7*R) } }, { { (fixed_t)(-.5*R), (fixed_t)( .7*R) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } }; #undef R #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) int ddt_cheating = 0; // killough 2/7/98: make global, rename to ddt_* static int leveljuststarted = 1; // kluge until AM_LevelInit() is called enum automapmode_e automapmode; // Mode that the automap is in // location of window on screen static int f_x; static int f_y; // size of window on screen static int f_w; static int f_h; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms each tic (map coords) static fixed_t ftom_zoommul; // how far the window zooms each tic (fb coords) static fixed_t m_x, m_y; // LL x,y window location on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y window location on the map (map coords) // // width/height of window on map (map coords) // static fixed_t m_w; static fixed_t m_h; // based on level size static fixed_t min_x; static fixed_t min_y; static fixed_t max_x; static fixed_t max_y; static fixed_t max_w; // max_x-min_x, static fixed_t max_h; // max_y-min_y // based on player size static fixed_t min_w; static fixed_t min_h; static fixed_t min_scale_mtof; // used to tell when to stop zooming out static fixed_t max_scale_mtof; // used to tell when to stop zooming in // old stuff for recovery later static fixed_t old_m_w, old_m_h; static fixed_t old_m_x, old_m_y; // old location used by the Follower routine static mpoint_t f_oldloc; // used by MTOF to scale from map-to-frame-buffer coords static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow // killough 2/22/98: Remove limit on automap marks, // and make variables external for use in savegames. mpoint_t *markpoints = NULL; // where the points are int markpointnum = 0; // next point to be assigned (also number of points now) int markpointnum_max = 0; // killough 2/22/98 static boolean stopped = true; // // AM_getIslope() // // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so // that it can be used with the brain-dead drawing stuff. // // Passed the line slope is desired for and an islope_t structure for return // Returns nothing // void AM_getIslope ( mline_t* ml, islope_t* is ) { int dx, dy; dy = ml->a.y - ml->b.y; dx = ml->b.x - ml->a.x; if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX); else is->islp = FixedDiv(dx, dy); if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX); else is->slp = FixedDiv(dy, dx); } // // AM_activateNewScale() // // Changes the map scale after zooming or translating // // Passed nothing, returns nothing // void AM_activateNewScale(void) { m_x += m_w/2; m_y += m_h/2; m_w = FTOM(f_w); m_h = FTOM(f_h); m_x -= m_w/2; m_y -= m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // AM_saveScaleAndLoc() // // Saves the current center and zoom // Affects the variables that remember old scale and loc // // Passed nothing, returns nothing // void AM_saveScaleAndLoc(void) { old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; } // // AM_restoreScaleAndLoc() // // restores the center and zoom from locally saved values // Affects global variables for location and scale // // Passed nothing, returns nothing // void AM_restoreScaleAndLoc(void) { m_w = old_m_w; m_h = old_m_h; if (!(automapmode & am_follow)) { m_x = old_m_x; m_y = old_m_y; } else { m_x = plr->mo->x - m_w/2; m_y = plr->mo->y - m_h/2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; // Change the scaling multipliers scale_mtof = FixedDiv(f_w<= markpointnum_max) markpoints = realloc(markpoints, (markpointnum_max = markpointnum_max ? markpointnum_max*2 : 16) * sizeof(*markpoints)); markpoints[markpointnum].x = m_x + m_w/2; markpoints[markpointnum].y = m_y + m_h/2; markpointnum++; } // // AM_findMinMaxBoundaries() // // Determines bounding box of all vertices, // sets global variables controlling zoom range. // // Passed nothing, returns nothing // void AM_findMinMaxBoundaries(void) { int i; fixed_t a; fixed_t b; min_x = min_y = INT_MAX; max_x = max_y = -INT_MAX; for (i=0;i max_x) max_x = vertexes[i].x; if (vertexes[i].y < min_y) min_y = vertexes[i].y; else if (vertexes[i].y > max_y) max_y = vertexes[i].y; } max_w = max_x - min_x; max_h = max_y - min_y; min_w = 2*PLAYERRADIUS; // const? never changed? min_h = 2*PLAYERRADIUS; a = FixedDiv(f_w< max_x) m_x = max_x - m_w/2; else if (m_x + m_w/2 < min_x) m_x = min_x - m_w/2; if (m_y + m_h/2 > max_y) m_y = max_y - m_h/2; else if (m_y + m_h/2 < min_y) m_y = min_y - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // AM_initVariables() // // Initialize the variables for the automap // // Affects the automap global variables // Status bar is notified that the automap has been entered // Passed nothing, returns nothing // void AM_initVariables(void) { int pnum; static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0 , 0 }; automapmode |= am_active; f_oldloc.x = INT_MAX; m_paninc.x = m_paninc.y = 0; ftom_zoommul = FRACUNIT; mtof_zoommul = FRACUNIT; m_w = FTOM(f_w); m_h = FTOM(f_h); // find player to center on initially if (!playeringame[pnum = consoleplayer]) for (pnum=0;pnummo->x - m_w/2; m_y = plr->mo->y - m_h/2; AM_changeWindowLoc(); // for saving & restoring old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; // inform the status bar of the change ST_Responder(&st_notify); } // // AM_loadPics() // void AM_loadPics(void) { // cph - mark numbers no longer needed cached } // // AM_unloadPics() // void AM_unloadPics(void) { // cph - mark numbers no longer needed cached } // // AM_clearMarks() // // Sets the number of marks to 0, thereby clearing them from the display // // Affects the global variable markpointnum // Passed nothing, returns nothing // void AM_clearMarks(void) { markpointnum = 0; } // // AM_LevelInit() // // Initialize the automap at the start of a new level // should be called at the start of every level // // Passed nothing, returns nothing // Affects automap's global variables // // CPhipps - get status bar height from status bar code void AM_LevelInit(void) { leveljuststarted = 0; f_x = f_y = 0; f_w = SCREENWIDTH; // killough 2/7/98: get rid of finit_ vars f_h = SCREENHEIGHT-ST_SCALED_HEIGHT;// to allow runtime setting of width/height AM_findMinMaxBoundaries(); scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT)); if (scale_mtof > max_scale_mtof) scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } // // AM_Stop() // // Cease automap operations, unload patches, notify status bar // // Passed nothing, returns nothing // void AM_Stop (void) { static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; AM_unloadPics(); automapmode &= ~am_active; ST_Responder(&st_notify); stopped = true; } // // AM_Start() // // Start up automap operations, // if a new level, or game start, (re)initialize level variables // init map variables // load mark patches // // Passed nothing, returns nothing // void AM_Start() { static int lastlevel = -1, lastepisode = -1; if (!stopped) AM_Stop(); stopped = false; if (lastlevel != gamemap || lastepisode != gameepisode) { AM_LevelInit(); lastlevel = gamemap; lastepisode = gameepisode; } AM_initVariables(); AM_loadPics(); } // // AM_minOutWindowScale() // // Set the window scale to the maximum size // // Passed nothing, returns nothing // void AM_minOutWindowScale() { scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // AM_maxOutWindowScale(void) // // Set the window scale to the minimum size // // Passed nothing, returns nothing // void AM_maxOutWindowScale(void) { scale_mtof = max_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // AM_Responder() // // Handle events (user inputs) in automap mode // // Passed an input event, returns true if its handled // boolean AM_Responder ( event_t* ev ) { int rc; static int cheatstate=0; static int bigstate=0; static char buffer[20]; int ch; // phares rc = false; if (!(automapmode & am_active)) { if (ev->type == ev_keydown && ev->data1 == key_map) // phares { AM_Start (); rc = true; } } else if (ev->type == ev_keydown) { rc = true; ch = ev->data1; // phares if (ch == key_map_right) // | if (!(automapmode & am_follow)) // V m_paninc.x = FTOM(F_PANINC); else rc = false; else if (ch == key_map_left) if (!(automapmode & am_follow)) m_paninc.x = -FTOM(F_PANINC); else rc = false; else if (ch == key_map_up) if (!(automapmode & am_follow)) m_paninc.y = FTOM(F_PANINC); else rc = false; else if (ch == key_map_down) if (!(automapmode & am_follow)) m_paninc.y = -FTOM(F_PANINC); else rc = false; else if (ch == key_map_zoomout) { mtof_zoommul = M_ZOOMOUT; ftom_zoommul = M_ZOOMIN; } else if (ch == key_map_zoomin) { mtof_zoommul = M_ZOOMIN; ftom_zoommul = M_ZOOMOUT; } else if (ch == key_map) { bigstate = 0; AM_Stop (); } else if (ch == key_map_gobig) { bigstate = !bigstate; if (bigstate) { AM_saveScaleAndLoc(); AM_minOutWindowScale(); } else AM_restoreScaleAndLoc(); } else if (ch == key_map_follow) { automapmode ^= am_follow; // CPhipps - put all automap mode stuff into one enum f_oldloc.x = INT_MAX; // Ty 03/27/98 - externalized plr->message = (automapmode & am_follow) ? s_AMSTR_FOLLOWON : s_AMSTR_FOLLOWOFF; } else if (ch == key_map_grid) { automapmode ^= am_grid; // CPhipps // Ty 03/27/98 - *not* externalized plr->message = (automapmode & am_grid) ? s_AMSTR_GRIDON : s_AMSTR_GRIDOFF; } else if (ch == key_map_mark) { // Ty 03/27/98 - *not* externalized snprintf(buffer, sizeof(buffer), "%s %d", s_AMSTR_MARKEDSPOT, markpointnum); plr->message = buffer; AM_addMark(); } else if (ch == key_map_clear) { AM_clearMarks(); // Ty 03/27/98 - *not* externalized plr->message = s_AMSTR_MARKSCLEARED; // ^ } // | else if (ch == key_map_rotate) { automapmode ^= am_rotate; plr->message = (automapmode & am_rotate) ? s_AMSTR_ROTATEON : s_AMSTR_ROTATEOFF; } else if (ch == key_map_overlay) { automapmode ^= am_overlay; plr->message = (automapmode & am_overlay) ? s_AMSTR_OVERLAYON : s_AMSTR_OVERLAYOFF; } else // phares { cheatstate=0; rc = false; } } else if (ev->type == ev_keyup) { rc = false; ch = ev->data1; if (ch == key_map_right) { if (!(automapmode & am_follow)) m_paninc.x = 0; } else if (ch == key_map_left) { if (!(automapmode & am_follow)) m_paninc.x = 0; } else if (ch == key_map_up) { if (!(automapmode & am_follow)) m_paninc.y = 0; } else if (ch == key_map_down) { if (!(automapmode & am_follow)) m_paninc.y = 0; } else if ((ch == key_map_zoomout) || (ch == key_map_zoomin)) { mtof_zoommul = FRACUNIT; ftom_zoommul = FRACUNIT; } } return rc; } // // AM_rotate() // // Rotation in 2D. // Used to rotate player arrow line character. // // Passed the coordinates of a point, and an angle // Returns the coordinates rotated by the angle // // CPhipps - made static & enhanced for automap rotation static void AM_rotate(fixed_t* x, fixed_t* y, angle_t a, fixed_t xorig, fixed_t yorig) { fixed_t tmpx; tmpx = FixedMul(*x - xorig,finecosine[a>>ANGLETOFINESHIFT]) - FixedMul(*y - yorig,finesine[a>>ANGLETOFINESHIFT]); *y = yorig + FixedMul(*x - xorig,finesine[a>>ANGLETOFINESHIFT]) + FixedMul(*y - yorig,finecosine[a>>ANGLETOFINESHIFT]); *x = tmpx + xorig; } // // AM_changeWindowScale() // // Automap zooming // // Passed nothing, returns nothing // void AM_changeWindowScale(void) { // Change the scaling multipliers scale_mtof = FixedMul(scale_mtof, mtof_zoommul); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); if (scale_mtof < min_scale_mtof) AM_minOutWindowScale(); else if (scale_mtof > max_scale_mtof/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2005 by Thom Johansen * * 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. * ****************************************************************************/ /* The following are assembler optimised version of the LPC filtering routines needed for FLAC decoding. They is optimised for use with the MCF5249 processor, or any other similar ColdFire core with the EMAC unit. */ /* This routine deals with sample widths 16 and lower. All LPC filtering up to order 10 is done in specially optimised unrolled loops, while every order above this is handled by a slower default routine. */ .section .icode,"ax",@progbits .global lpc_decode_emac .align 2 lpc_decode_emac: lea.l (-44, %sp), %sp movem.l %d2-%d7/%a2-%a6, (%sp) movem.l (44+4, %sp), %d0-%d2/%a0-%a1 /* d0 = blocksize, d1 = qlevel, d2 = pred_order a0 = data, a1 = coeffs */ /* the data pointer always lags behind history pointer by 'pred_order' samples. since we have one loop for each order, we can hard code this and free a register by not saving data pointer. */ move.l %d2, %d3 neg.l %d3 lea.l (%a0, %d3.l*4), %a0 | history clr.l %d3 move.l %d3, %macsr | we'll need integer mode for this tst.l %d0 jeq .exit | zero samples to process, exit moveq.l #10, %d3 cmp.l %d3, %d2 jgt .default | order is over 10, jump to default case jmp.l (2, %pc, %d2.l*4) | jump to loop corresponding to pred_order | jumptable: bra.w .exit | zero order filter isn't possible, exit function bra.w .order1 bra.w .order2 bra.w .order3 bra.w .order4 bra.w .order5 bra.w .order6 bra.w .order7 bra.w .order8 bra.w .order9 | last jump table entry coincides with target, so leave it out .order10: movem.l (%a1), %d3-%d7/%a1-%a5 | load lpc coefs move.l (%a0)+, %a6 | load first history sample 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (%a0)+, %a6, %acc0 mac.l %a6, %d6, (%a0)+, %a6, %acc0 mac.l %a6, %d5, (%a0)+, %a6, %acc0 mac.l %a6, %d4, (%a0)+, %a6, %acc0 mac.l %a6, %d3, (-9*4, %a0), %a6, %acc0 | load for the next iteration movclr.l %acc0, %d2 | get sum asr.l %d1, %d2 | shift sum by qlevel bits add.l %d2, (%a0) | add residual and save lea.l (-8*4, %a0), %a0 | point history back at second element subq.l #1, %d0 | decrement sample count jne 1b | are we done? jra .exit .order9: movem.l (%a1), %d4-%d7/%a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (%a0)+, %a6, %acc0 mac.l %a6, %d6, (%a0)+, %a6, %acc0 mac.l %a6, %d5, (%a0)+, %a6, %acc0 mac.l %a6, %d4, (-8*4, %a0), %a6, %acc0 movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) lea.l (-7*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .order8: movem.l (%a1), %d5-%d7/%a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (%a0)+, %a6, %acc0 mac.l %a6, %d6, (%a0)+, %a6, %acc0 mac.l %a6, %d5, (-7*4, %a0), %a6, %acc0 movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) lea.l (-6*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .order7: movem.l (%a1), %d6-%d7/%a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (%a0)+, %a6, %acc0 mac.l %a6, %d6, (-6*4, %a0), %a6, %acc0 movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) lea.l (-5*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .order6: movem.l (%a1), %d7/%a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (-5*4, %a0), %a6, %acc0 movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) lea.l (-4*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .order5: movem.l (%a1), %a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (-4*4, %a0), %a6, %acc0 movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) lea.l (-3*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .order4: movem.l (%a1), %a2-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (-3*4, %a0), %a6, %acc0 movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) subq.l #8, %a0 subq.l #1, %d0 jne 1b jra .exit .order3: movem.l (%a1), %a3-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (-2*4, %a0), %a6, %acc0 movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) subq.l #4, %a0 subq.l #1, %d0 jne 1b jra .exit .order2: movem.l (%a1), %a4-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, %acc0 | data for next iteration is already loaded movclr.l %acc0, %d2 asr.l %d1, %d2 add.l %d2, (%a0) subq.l #1, %d0 jne 1b jra .exit .order1: | no point in using mac here move.l (%a1), %a5 1: move.l %a5, %d2 muls.l (%a0)+, %d2 asr.l %d1, %d2 add.l %d2, (%a0) subq.l #1, %d0 jne 1b jra .exit .default: /* we do the filtering in an unrolled by 4 loop as far as we can, and then do the rest by jump table. */ lea.l (%a1, %d2.l*4), %a2 | need to start in the other end of coefs move.l %a0, %a3 | working copy of history pointer move.l %d2, %d3 lsr.l #2, %d3 | coefs/4, num of iterations needed in next loop move.l (%a3)+, %a5 | preload data for loop 1: lea.l (-4*4, %a2), %a2 | move lpc coef pointer four samples backwards movem.l (%a2), %d4-%d7 | load four coefs mac.l %a5, %d7, (%a3)+, %a5, %acc0 mac.l %a5, %d6, (%a3)+, %a5, %acc0 mac.l %a5, %d5, (%a3)+, %a5, %acc0 mac.l %a5, %d4, (%a3)+, %a5, %acc0 subq.l #1, %d3 | any more unrolled loop operations left? jne 1b moveq.l #3, %d3 | mask 0x00000003 and.l %d2, %d3 | get the remaining samples to be filtered jmp.l (2, %pc, %d3*2) | then jump into mac.l chain | jumptable: bra.b 3f | none left bra.b 2f | one left bra.b 1f | two left | three left move.l -(%a2), %d4 mac.l %a5, %d4, (%a3)+, %a5, %acc0 1: move.l -(%a2), %d4 mac.l %a5, %d4, (%a3)+, %a5, %acc0 2: move.l -(%a2), %d4 mac.l %a5, %d4, (%a3)+, %a5, %acc0 3: movclr.l %acc0, %d3 | get result asr.l %d1, %d3 | shift qlevel bits right add.l %a5, %d3 | add residual, which is in a5 by now move.l %d3, -(%a3) | save, a3 is also one past save location addq.l #4, %a0 | increment history pointer subq.l #1, %d0 | decrement sample count jne .default | are we done? jra .exit | if so, fall through to exit /* This routine deals with sample widths 24 and lower. All LPC filtering up to order 8 is done in specially optimised unrolled loops, while every order above this is handled by a slower default routine. */ .global lpc_decode_emac_wide .align 2 lpc_decode_emac_wide: lea.l (-44, %sp), %sp movem.l %d2-%d7/%a2-%a6, (%sp) movem.l (44+4, %sp), %d0-%d1/%d3/%a0-%a1 /* d0 = blocksize, d1 = qlevel, d3 = pred_order a0 = data, a1 = coeffs */ /* the data pointer always lags behind history pointer by 'pred_order' samples. since we have one loop for each order, we can hard code this and free a register by not saving data pointer. */ move.l %d3, %d2 neg.l %d2 lea.l (%a0, %d2.l*4), %a0 | history clr.l %d2 move.l %d2, %macsr | we'll need integer mode for this tst.l %d0 jeq .exit | zero samples to process, exit moveq.l #32, %d2 sub.l %d1, %d2 | calculate shift amount for extension byte moveq.l #8, %d4 cmp.l %d4, %d3 jgt .wdefault | order is over 8, jump to default case jmp.l (2, %pc, %d3.l*4) | jump to loop corresponding to pred_order | jumptable: bra.w .exit | zero order filter isn't possible, exit function bra.w .worder1 bra.w .worder2 bra.w .worder3 bra.w .worder4 bra.w .worder5 bra.w .worder6 bra.w .worder7 | last jump table entry coincides with target, so leave it out .worder8: movem.l (%a1), %d5-%d7/%a1-%a5 | load lpc coefs move.l (%a0)+, %a6 | load first history sample 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (%a0)+, %a6, %acc0 mac.l %a6, %d6, (%a0)+, %a6, %acc0 mac.l %a6, %d5, (-7*4, %a0), %a6, %acc0 | load for the next iteration move.l %accext01, %d4 | get top 8 bits of sum movclr.l %acc0, %d3 | then botten 32 bits lsr.l %d1, %d3 | shift bottom bits qlevel bits right asl.l %d2, %d4 | shift top bits 32 - qlevel bits left or.l %d4, %d3 | now combine results add.l %d3, (%a0) | add residual and save lea.l (-6*4, %a0), %a0 | point history back at second element subq.l #1, %d0 | decrement sample count jne 1b | are we done? jra .exit .worder7: movem.l (%a1), %d6-%d7/%a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (%a0)+, %a6, %acc0 mac.l %a6, %d6, (-6*4, %a0), %a6, %acc0 move.l %accext01, %d4 movclr.l %acc0, %d3 lsr.l %d1, %d3 asl.l %d2, %d4 or.l %d4, %d3 add.l %d3, (%a0) lea.l (-5*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .worder6: movem.l (%a1), %d7/%a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (%a0)+, %a6, %acc0 mac.l %a6, %d7, (-5*4, %a0), %a6, %acc0 move.l %accext01, %d4 movclr.l %acc0, %d3 lsr.l %d1, %d3 asl.l %d2, %d4 or.l %d4, %d3 add.l %d3, (%a0) lea.l (-4*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .worder5: movem.l (%a1), %a1-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (%a0)+, %a6, %acc0 mac.l %a6, %a1, (-4*4, %a0), %a6, %acc0 move.l %accext01, %d4 movclr.l %acc0, %d3 lsr.l %d1, %d3 asl.l %d2, %d4 or.l %d4, %d3 add.l %d3, (%a0) lea.l (-3*4, %a0), %a0 subq.l #1, %d0 jne 1b jra .exit .worder4: movem.l (%a1), %a2-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (%a0)+, %a6, %acc0 mac.l %a6, %a2, (-3*4, %a0), %a6, %acc0 move.l %accext01, %d4 movclr.l %acc0, %d3 lsr.l %d1, %d3 asl.l %d2, %d4 or.l %d4, %d3 add.l %d3, (%a0) subq.l #8, %a0 subq.l #1, %d0 jne 1b jra .exit .worder3: movem.l (%a1), %a3-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, (%a0)+, %a6, %acc0 mac.l %a6, %a3, (-2*4, %a0), %a6, %acc0 move.l %accext01, %d4 movclr.l %acc0, %d3 lsr.l %d1, %d3 asl.l %d2, %d4 or.l %d4, %d3 add.l %d3, (%a0) subq.l #4, %a0 subq.l #1, %d0 jne 1b jra .exit .worder2: movem.l (%a1), %a4-%a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0)+, %a6, %acc0 mac.l %a6, %a4, %acc0 | data for next iteration is already loaded move.l %accext01, %d4 movclr.l %acc0, %d3 lsr.l %d1, %d3 asl.l %d2, %d4 or.l %d4, %d3 add.l %d3, (%a0) subq.l #1, %d0 jne 1b jra .exit .worder1: move.l (%a1), %a5 move.l (%a0)+, %a6 1: mac.l %a6, %a5, (%a0), %a6, %acc0 move.l %accext01, %d4 movclr.l %acc0, %d3 lsr.l %d1, %d3 asl.l %d2, %d4 or.l %d4, %d3 add.l %a6, %d3 | residual is already in a6 move.l %d3, (%a0)+ subq.l #1, %d0 jne 1b jra .exit .wdefault: /* we do the filtering in an unrolled by 4 loop as far as we can, and then do the rest by jump table. */ lea.l (%a1, %d3.l*4), %a2 | need to start in the other end of coefs move.l %a0, %a3 | working copy of history pointer move.l %d3, %d4 lsr.l #2, %d4 | coefs/4, num of iterations needed in next loop move.l (%a3)+, %a5 | preload data for loop 1: lea.l (-4*4, %a2), %a2 | move lpc coef pointer four samples backwards movem.l (%a2), %d5-%d7/%a4 | load four coefs mac.l %a5, %a4, (%a3)+, %a5, %acc0 mac.l %a5, %d7, (%a3)+, %a5, %acc0 mac.l %a5, %d6, (%a3)+, %a5, %acc0 mac.l %a5, %d5, (%a3)+, %a5, %acc0 subq.l #1, %d4 | any more unrolled loop operations left? jne 1b moveq.l #3, %d4 | mask 0x00000003 and.l %d3, %d4 | get the remaining samples to be filtered jmp.l (2, %pc, %d4*2) | then jump into mac.l chain | jumptable: bra.b 3f | none left bra.b 2f | one left bra.b 1f | two left | three left move.l -(%a2), %d4 mac.l %a5, %d4, (%a3)+, %a5, %acc0 1: move.l -(%a2), %d4 mac.l %a5, %d4, (%a3)+, %a5, %acc0 2: move.l -(%a2), %d4 mac.l %a5, %d4, (%a3)+, %a5, %acc0 3: move.l %accext01, %d5 | get high 32 bits of result movclr.l %acc0, %d4 | get low 32 bits of result lsr.l %d1, %d4 | shift qlevel bits right asl.l %d2, %d5 | shift 32 - qlevel bits left or.l %d5, %d4 | combine top and low bits after shift add.l %a5, %d4 | add residual, which is in a5 by now move.l %d4, -(%a3) | save, a3 is also one past save location addq.l #4, %a0 | increment history pointer subq.l #1, %d0 | decrement sample count jne .wdefault | are we done? | if so, fall through to exit .exit: movem.l (%sp), %d2-%d7/%a2-%a6 lea.l (44, %sp), %sp rts