1/* 2 * (C) Copyright 2002 3 * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24/* This file is largely based on code obtned from AMD. AMD's original 25 * copyright is included below 26 */ 27 28/* TITLE SIZER - Aspen DRAM Sizing Routine. 29 * ============================================================================= 30 * 31 * Copyright 1999 Advanced Micro Devices, Inc. 32 * You may redistribute this program and/or modify this program under the terms 33 * of the GNU General Public License as published by the Free Software Foundation; 34 * either version 2 of the License, or (at your option) any later version. 35 * 36 * This program is distributed WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 37 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU 38 * General Public License for more details. 39 * 40 * You should have received a copy of the GNU General Public License along with 41 * this program; if not, write to the Free Software Foundation, Inc., 42 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 43 * 44 * THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY 45 * OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF 46 * THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE. 47 * IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER 48 * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS 49 * INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR INABILITY 50 * TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGES. BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR 52 * LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE 53 * LIMITATION MAY NOT APPLY TO YOU. 54 * 55 * AMD does not assume any responsibility for any errors that may appear in 56 * the Materials nor any responsibility to support or update the Materials. 57 * AMD retains the right to make changes to its test specifications at any 58 * time, without notice. 59 * ============================================================================== 60 */ 61 62/* 63 ****************************************************************************** 64 * 65 * FILE : sizer.asm - SDRAM DIMM Sizing Algorithm 66 * 67 * 68 * 69 * FUNCTIONS : sizemem() - jumped to, not called. To be executed after 70 * reset to determine the size of the SDRAM DIMMs. Initializes 71 * the memory subsystem. 72 * 73 * 74 * AUTHOR : Buddy Fey - Original. 75 * 76 * 77 * DESCRIPTION : Performs sizing on SDRAM DIMMs on ASPEN processor. 78 * NOTE: This is a small memory model version 79 * 80 * 81 * INPUTS : BP contains return address offset 82 * CACHE is assumed to be disabled. 83 * The FS segment limit has already been set to big real mode 84 * (full 32-bit addressing capability) 85 * 86 * 87 * OUTPUTS : None 88 * 89 * 90 * REG USE : ax,bx,cx,dx,di,si,bp, fs 91 * 92 * 93 * REVISION : See PVCS info below 94 * 95 * 96 * TEST PLAN CROSS REFERENCE: 97 * 98 * 99 * $Workfile: $ 100 * $Revision: 1.2 $ 101 * $Date: 1999/09/22 12:49:33 $ 102 * $Author: chipf $ 103 * $Log: sizer.asm $ 104 * Revision 1.2 1999/09/22 12:49:33 chipf 105 * Add legal header 106 * 107 ******************************************************************************* 108 */ 109 110 111/******************************************************************************* 112 * FUNCTIONAL DESCRIPTION: 113 * This routine is called to autodetect the geometry of the DRAM. 114 * 115 * This routine is called to determine the number of column bits for the DRAM 116 * devices in this external bank. This routine assumes that the external bank 117 * has been configured for an 11-bit column and for 4 internal banks. This gives 118 * us the maximum address reach in memory. By writing a test value to the max 119 * address and locating where it aliases to, we can determine the number of valid 120 * column bits. 121 * 122 * This routine is called to determine the number of internal banks each DRAM 123 * device has. The external bank (under test) is configured for maximum reach 124 * with 11-bit columns and 4 internal banks. This routine will write to a max 125 * address (BA1 and BA0 = 1) and then read from an address with BA1=0 to see if 126 * that column is a "don't care". If BA1 does not affect write/read of data, 127 * then this device has only 2 internal banks. 128 * 129 * This routine is called to determine the ending address for this external 130 * bank of SDRAM. We write to a max address with a data value and then disable 131 * row address bits looking for "don't care" locations. Each "don't care" bit 132 * represents a dividing of the maximum density (128M) by 2. By dividing the 133 * maximum of 32 4M chunks in an external bank down by all the "don't care" bits 134 * determined during sizing, we set the proper density. 135 * 136 * WARNINGS. 137 * bp must be preserved because it is used for return linkage. 138 * 139 * EXIT 140 * nothing returned - but the memory subsystem is enabled 141 ******************************************************************************* 142 */ 143 144#include <config.h> 145 146.section .text 147.equ DRCCTL, 0x0fffef010 /* DRAM control register */ 148.equ DRCTMCTL, 0x0fffef012 /* DRAM timing control register */ 149.equ DRCCFG, 0x0fffef014 /* DRAM bank configuration register */ 150.equ DRCBENDADR, 0x0fffef018 /* DRAM bank ending address register */ 151.equ ECCCTL, 0x0fffef020 /* DRAM ECC control register */ 152.equ ECCINT, 0x0fffefd18 /* DRAM ECC nmi-INT mapping */ 153.equ DBCTL, 0x0fffef040 /* DRAM buffer control register */ 154 155.equ CACHELINESZ, 0x00000010 /* size of our cache line (read buffer) */ 156.equ COL11_ADR, 0x0e001e00 /* 11 col addrs */ 157.equ COL10_ADR, 0x0e000e00 /* 10 col addrs */ 158.equ COL09_ADR, 0x0e000600 /* 9 col addrs */ 159.equ COL08_ADR, 0x0e000200 /* 8 col addrs */ 160.equ ROW14_ADR, 0x0f000000 /* 14 row addrs */ 161.equ ROW13_ADR, 0x07000000 /* 13 row addrs */ 162.equ ROW12_ADR, 0x03000000 /* 12 row addrs */ 163.equ ROW11_ADR, 0x01000000 /* 11 row addrs/also bank switch */ 164.equ ROW10_ADR, 0x00000000 /* 10 row addrs/also bank switch */ 165.equ COL11_DATA, 0x0b0b0b0b /* 11 col addrs */ 166.equ COL10_DATA, 0x0a0a0a0a /* 10 col data */ 167.equ COL09_DATA, 0x09090909 /* 9 col data */ 168.equ COL08_DATA, 0x08080808 /* 8 col data */ 169.equ ROW14_DATA, 0x3f3f3f3f /* 14 row data (MASK) */ 170.equ ROW13_DATA, 0x1f1f1f1f /* 13 row data (MASK) */ 171.equ ROW12_DATA, 0x0f0f0f0f /* 12 row data (MASK) */ 172.equ ROW11_DATA, 0x07070707 /* 11 row data/also bank switch (MASK) */ 173.equ ROW10_DATA, 0xaaaaaaaa /* 10 row data/also bank switch (MASK) */ 174 175 176 /* 177 * initialize dram controller registers 178 */ 179.globl mem_init 180mem_init: 181 xorw %ax,%ax 182 movl $DBCTL, %edi 183 movb %al, (%edi) /* disable write buffer */ 184 185 movl $ECCCTL, %edi 186 movb %al, (%edi) /* disable ECC */ 187 188 movl $DRCTMCTL, %edi 189 movb $0x1E,%al /* Set SDRAM timing for slowest */ 190 movb %al, (%edi) 191 192 /* 193 * setup loop to do 4 external banks starting with bank 3 194 */ 195 movl $0xff000000,%eax /* enable last bank and setup */ 196 movl $DRCBENDADR, %edi /* ending address register */ 197 movl %eax, (%edi) 198 199 movl $DRCCFG, %edi /* setup */ 200 movw $0xbbbb,%ax /* dram config register for */ 201 movw %ax, (%edi) 202 203 /* 204 * issue a NOP to all DRAMs 205 */ 206 movl $DRCCTL, %edi /* setup DRAM control register with */ 207 movb $0x1,%al /* Disable refresh,disable write buffer */ 208 movb %al, (%edi) 209 movl $CACHELINESZ, %esi /* just a dummy address to write for */ 210 movw %ax, (%esi) 211 /* 212 * delay for 100 usec? 200? 213 * ******this is a cludge for now ************* 214 */ 215 movw $100,%cx 216sizdelay: 217 loop sizdelay /* we need 100 usec here */ 218 /***********************************************/ 219 220 /* 221 * issue all banks precharge 222 */ 223 movb $0x2,%al /* All banks precharge */ 224 movb %al, (%edi) 225 movw %ax, (%esi) 226 227 /* 228 * issue 2 auto refreshes to all banks 229 */ 230 movb $0x4,%al /* Auto refresh cmd */ 231 movb %al, (%edi) 232 movw $2,%cx 233refresh1: 234 movw %ax, (%esi) 235 loop refresh1 236 237 /* 238 * issue LOAD MODE REGISTER command 239 */ 240 movb $0x3,%al /* Load mode register cmd */ 241 movb %al, (%edi) 242 movw %ax, (%esi) 243 244 /* 245 * issue 8 more auto refreshes to all banks 246 */ 247 movb $0x4,%al /* Auto refresh cmd */ 248 movb %al, (%edi) 249 movw $8,%cx 250refresh2: 251 movw %ax, (%esi) 252 loop refresh2 253 254 /* 255 * set control register to NORMAL mode 256 */ 257 movb $0x0,%al /* Normal mode value */ 258 movb %al, (%edi) 259 260 /* 261 * size dram starting with external bank 3 moving to external bank 0 262 */ 263 movl $0x3,%ecx /* start with external bank 3 */ 264 265nextbank: 266 267 /* 268 * write col 11 wrap adr 269 */ 270 movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ 271 movl $COL11_DATA, %eax /* pattern for max supported columns(11) */ 272 movl %eax, (%esi) /* write max col pattern at max col adr */ 273 movl (%esi), %ebx /* optional read */ 274 cmpl %ebx,%eax /* to verify write */ 275 jnz bad_ram /* this ram is bad */ 276 /* 277 * write col 10 wrap adr 278 */ 279 280 movl $COL10_ADR, %esi /* set address to 10 col wrap address */ 281 movl $COL10_DATA, %eax /* pattern for 10 col wrap */ 282 movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */ 283 movl (%esi), %ebx /* optional read */ 284 cmpl %ebx,%eax /* to verify write */ 285 jnz bad_ram /* this ram is bad */ 286 /* 287 * write col 9 wrap adr 288 */ 289 movl $COL09_ADR, %esi /* set address to 9 col wrap address */ 290 movl $COL09_DATA, %eax /* pattern for 9 col wrap */ 291 movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */ 292 movl (%esi), %ebx /* optional read */ 293 cmpl %ebx,%eax /* to verify write */ 294 jnz bad_ram /* this ram is bad */ 295 /* 296 * write col 8 wrap adr 297 */ 298 movl $COL08_ADR, %esi /* set address to min(8) col wrap address */ 299 movl $COL08_DATA, %eax /* pattern for min (8) col wrap */ 300 movl %eax, (%esi) /* write min col pattern @ min col adr */ 301 movl (%esi), %ebx /* optional read */ 302 cmpl %ebx,%eax /* to verify write */ 303 jnz bad_ram /* this ram is bad */ 304 /* 305 * write row 14 wrap adr 306 */ 307 movl $ROW14_ADR, %esi /* set address to max row (14) wrap addr */ 308 movl $ROW14_DATA, %eax /* pattern for max supported rows(14) */ 309 movl %eax, (%esi) /* write max row pattern at max row adr */ 310 movl (%esi), %ebx /* optional read */ 311 cmpl %ebx,%eax /* to verify write */ 312 jnz bad_ram /* this ram is bad */ 313 /* 314 * write row 13 wrap adr 315 */ 316 movl $ROW13_ADR, %esi /* set address to 13 row wrap address */ 317 movl $ROW13_DATA, %eax /* pattern for 13 row wrap */ 318 movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */ 319 movl (%esi), %ebx /* optional read */ 320 cmpl %ebx,%eax /* to verify write */ 321 jnz bad_ram /* this ram is bad */ 322 /* 323 * write row 12 wrap adr 324 */ 325 movl $ROW12_ADR, %esi /* set address to 12 row wrap address */ 326 movl $ROW12_DATA, %eax /* pattern for 12 row wrap */ 327 movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */ 328 movl (%esi), %ebx /* optional read */ 329 cmpl %ebx,%eax /* to verify write */ 330 jnz bad_ram /* this ram is bad */ 331 /* 332 * write row 11 wrap adr 333 */ 334 movl $ROW11_ADR, %edi /* set address to 11 row wrap address */ 335 movl $ROW11_DATA, %eax /* pattern for 11 row wrap */ 336 movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */ 337 movl (%edi), %ebx /* optional read */ 338 cmpl %ebx,%eax /* to verify write */ 339 jnz bad_ram /* this ram is bad */ 340 /* 341 * write row 10 wrap adr --- this write is really to determine number of banks 342 */ 343 movl $ROW10_ADR, %edi /* set address to 10 row wrap address */ 344 movl $ROW10_DATA, %eax /* pattern for 10 row wrap (AA) */ 345 movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */ 346 movl (%edi), %ebx /* optional read */ 347 cmpl %ebx,%eax /* to verify write */ 348 jnz bad_ram /* this ram is bad */ 349 /* 350 * read data @ row 12 wrap adr to determine * banks, 351 * and read data @ row 14 wrap adr to determine * rows. 352 * if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM. 353 * if data @ row 12 wrap == AA, we only have 2 banks, NOT 4 354 * if data @ row 12 wrap == 11 or 12, we have 4 banks, 355 */ 356 xorw %di,%di /* value for 2 banks in DI */ 357 movl (%esi), %ebx /* read from 12 row wrap to check banks 358 * (esi is setup from the write to row 12 wrap) */ 359 cmpl %ebx,%eax /* check for AA pattern (eax holds the aa pattern) */ 360 jz only2 /* if pattern == AA, we only have 2 banks */ 361 362 /* 4 banks */ 363 364 movw $8,%di /* value for 4 banks in DI (BNK_CNT bit) */ 365 cmpl $ROW11_DATA, %ebx /* only other legitimate values are 11 */ 366 jz only2 367 cmpl $ROW12_DATA, %ebx /* and 12 */ 368 jnz bad_ram /* its bad if not 11 or 12! */ 369 370 /* fall through */ 371only2: 372 /* 373 * validate row mask 374 */ 375 movl $ROW14_ADR, %esi /* set address back to max row wrap addr */ 376 movl (%esi), %eax /* read actual number of rows @ row14 adr */ 377 378 cmpl $ROW11_DATA, %eax /* row must be greater than 11 pattern */ 379 jb bad_ram 380 381 cmpl $ROW14_DATA, %eax /* and row must be less than 14 pattern */ 382 ja bad_ram 383 384 cmpb %ah,%al /* verify all 4 bytes of dword same */ 385 jnz bad_ram 386 movl %eax,%ebx 387 shrl $16,%ebx 388 cmpw %bx,%ax 389 jnz bad_ram 390 /* 391 * read col 11 wrap adr for real column data value 392 */ 393 movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ 394 movl (%esi), %eax /* read real col number at max col adr */ 395 /* 396 * validate column data 397 */ 398 cmpl $COL08_DATA, %eax /* col must be greater than 8 pattern */ 399 jb bad_ram 400 401 cmpl $COL11_DATA, %eax /* and row must be less than 11 pattern */ 402 ja bad_ram 403 404 subl $COL08_DATA, %eax /* normalize column data to zero */ 405 jc bad_ram 406 cmpb %ah,%al /* verify all 4 bytes of dword equal */ 407 jnz bad_ram 408 movl %eax,%edx 409 shrl $16,%edx 410 cmpw %dx,%ax 411 jnz bad_ram 412 /* 413 * merge bank and col data together 414 */ 415 addw %di,%dx /* merge of bank and col info in dl */ 416 /* 417 * fix ending addr mask based upon col info 418 */ 419 movb $3,%al 420 subb %dh,%al /* dh contains the overflow from the bank/col merge */ 421 movb %bl,%dh /* bl contains the row mask (aa, 07, 0f, 1f or 3f) */ 422 xchgw %cx,%ax /* cx = ax = 3 or 2 depending on 2 or 4 bank device */ 423 shrb %cl,%dh /* */ 424 incb %dh /* ending addr is 1 greater than real end */ 425 xchgw %cx,%ax /* cx is bank number again */ 426 /* 427 * issue all banks precharge 428 */ 429bad_reint: 430 movl $DRCCTL, %esi /* setup DRAM control register with */ 431 movb $0x2,%al /* All banks precharge */ 432 movb %al, (%esi) 433 movl $CACHELINESZ, %esi /* address to init read buffer */ 434 movw %ax, (%esi) 435 436 /* 437 * update ENDING ADDRESS REGISTER 438 */ 439 movl $DRCBENDADR, %edi /* DRAM ending address register */ 440 movl %ecx,%ebx 441 addl %ebx, %edi 442 movb %dh, (%edi) 443 /* 444 * update CONFIG REGISTER 445 */ 446 xorb %dh,%dh 447 movw $0x00f,%bx 448 movw %cx,%ax 449 shlw $2,%ax 450 xchgw %cx,%ax 451 shlw %cl,%dx 452 shlw %cl,%bx 453 notw %bx 454 xchgw %cx,%ax 455 movl $DRCCFG, %edi 456 mov (%edi), %ax 457 andw %bx,%ax 458 orw %dx,%ax 459 movw %ax, (%edi) 460 jcxz cleanup 461 462 decw %cx 463 movl %ecx,%ebx 464 movl $DRCBENDADR, %edi /* DRAM ending address register */ 465 movb $0xff,%al 466 addl %ebx, %edi 467 movb %al, (%edi) 468 /* 469 * set control register to NORMAL mode 470 */ 471 movl $DRCCTL, %esi /* setup DRAM control register with */ 472 movb $0x0,%al /* Normal mode value */ 473 movb %al, (%esi) 474 movl $CACHELINESZ, %esi /* address to init read buffer */ 475 movw %ax, (%esi) 476 jmp nextbank 477 478cleanup: 479 movl $DRCBENDADR, %edi /* DRAM ending address register */ 480 movw $4,%cx 481 xorw %ax,%ax 482cleanuplp: 483 movb (%edi), %al 484 orb %al,%al 485 jz emptybank 486 487 addb %ah,%al 488 jns nottoomuch 489 490 movb $0x7f,%al 491nottoomuch: 492 movb %al,%ah 493 orb $0x80,%al 494 movb %al, (%edi) 495emptybank: 496 incl %edi 497 loop cleanuplp 498 499#if defined CONFIG_SYS_SDRAM_DRCTMCTL 500 /* just have your hardware desinger _GIVE_ you what you need here! */ 501 movl $DRCTMCTL, %edi 502 movb $CONFIG_SYS_SDRAM_DRCTMCTL,%al 503 movb %al, (%edi) 504#else 505#if defined(CONFIG_SYS_SDRAM_CAS_LATENCY_2T) || defined(CONFIG_SYS_SDRAM_CAS_LATENCY_3T) 506 /* set the CAS latency now since it is hard to do 507 * when we run from the RAM */ 508 movl $DRCTMCTL, %edi /* DRAM timing register */ 509 movb (%edi), %al 510#ifdef CONFIG_SYS_SDRAM_CAS_LATENCY_2T 511 andb $0xef, %al 512#endif 513#ifdef CONFIG_SYS_SDRAM_CAS_LATENCY_3T 514 orb $0x10, %al 515#endif 516 movb %al, (%edi) 517#endif 518#endif 519 movl $DRCCTL, %edi /* DRAM Control register */ 520 movb $0x3,%al /* Load mode register cmd */ 521 movb %al, (%edi) 522 movw %ax, (%esi) 523 524 525 movl $DRCCTL, %edi /* DRAM Control register */ 526 movb $0x18,%al /* Enable refresh and NORMAL mode */ 527 movb %al, (%edi) 528 529 jmp dram_done 530 531bad_ram: 532 xorl %edx,%edx 533 xorl %edi,%edi 534 jmp bad_reint 535 536dram_done: 537 538#if CONFIG_SYS_SDRAM_ECC_ENABLE 539 /* 540 * We are in the middle of an existing 'call' - Need to store the 541 * existing return address before making another 'call' 542 */ 543 movl %ebp, %ebx 544 545 /* Get the memory size */ 546 movl $init_ecc, %ebp 547 jmpl get_mem_size 548 549init_ecc: 550 /* Restore the orignal return address */ 551 movl %ebx, %ebp 552 553 /* A nominal memory test: just a byte at each address line */ 554 movl %eax, %ecx 555 shrl $0x1, %ecx 556 movl $0x1, %edi 557memtest0: 558 movb $0xa5, (%edi) 559 cmpb $0xa5, (%edi) 560 jne out 561 shrl $1, %ecx 562 andl %ecx,%ecx 563 jz set_ecc 564 shll $1, %edi 565 jmp memtest0 566 567set_ecc: 568 /* clear all ram with a memset */ 569 movl %eax, %ecx 570 xorl %esi, %esi 571 xorl %edi, %edi 572 xorl %eax, %eax 573 shrl $2, %ecx 574 cld 575 rep stosl 576 /* enable read, write buffers */ 577 movb $0x11, %al 578 movl $DBCTL, %edi 579 movb %al, (%edi) 580 /* enable NMI mapping for ECC */ 581 movl $ECCINT, %edi 582 mov $0x10, %al 583 movb %al, (%edi) 584 /* Turn on ECC */ 585 movl $ECCCTL, %edi 586 mov $0x05, %al 587 movb %al, (%edi) 588#endif 589 590out: 591 jmp *%ebp 592 593/* 594 * Read and decode the sc520 DRCBENDADR MMCR and return the number of 595 * available ram bytes in %eax 596 */ 597.globl get_mem_size 598get_mem_size: 599 movl $DRCBENDADR, %edi /* DRAM ending address register */ 600 601bank0: movl (%edi), %eax 602 movl %eax, %ecx 603 andl $0x00000080, %ecx 604 jz bank1 605 andl $0x0000007f, %eax 606 shll $22, %eax 607 movl %eax, %ebx 608 609bank1: movl (%edi), %eax 610 movl %eax, %ecx 611 andl $0x00008000, %ecx 612 jz bank2 613 andl $0x00007f00, %eax 614 shll $14, %eax 615 movl %eax, %ebx 616 617bank2: movl (%edi), %eax 618 movl %eax, %ecx 619 andl $0x00800000, %ecx 620 jz bank3 621 andl $0x007f0000, %eax 622 shll $6, %eax 623 movl %eax, %ebx 624 625bank3: movl (%edi), %eax 626 movl %eax, %ecx 627 andl $0x80000000, %ecx 628 jz done 629 andl $0x7f000000, %eax 630 shrl $2, %eax 631 movl %eax, %ebx 632 633done: 634 movl %ebx, %eax 635 jmp *%ebp 636