Annotation of gcc/config/h8300/lib1funcs.asm, revision 1.1.1.2

1.1       root        1: ;; libgcc1 routines for the Hitachi h8/300 cpu.
                      2: ;; Contributed by Steve Chamberlain.
                      3: ;; [email protected]
                      4: 
                      5: /* Copyright (C) 1994 Free Software Foundation, Inc.
                      6: 
                      7: This file is free software; you can redistribute it and/or modify it
                      8: under the terms of the GNU General Public License as published by the
                      9: Free Software Foundation; either version 2, or (at your option) any
                     10: later version.
                     11: 
                     12: In addition to the permissions in the GNU General Public License, the
                     13: Free Software Foundation gives you unlimited permission to link the
                     14: compiled version of this file with other programs, and to distribute
                     15: those programs without any restriction coming from the use of this
                     16: file.  (The General Public License restrictions do apply in other
                     17: respects; for example, they cover modification of the file, and
                     18: distribution when not linked into another program.)
                     19: 
                     20: This file is distributed in the hope that it will be useful, but
                     21: WITHOUT ANY WARRANTY; without even the implied warranty of
                     22: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     23: General Public License for more details.
                     24: 
                     25: You should have received a copy of the GNU General Public License
                     26: along with this program; see the file COPYING.  If not, write to
1.1.1.2 ! root       27: the Free Software Foundation, 59 Temple Place - Suite 330,
        !            28: Boston, MA 02111-1307, USA.  */
1.1       root       29: 
                     30: /* As a special exception, if you link this library with other files,
                     31:    some of which are compiled with GCC, to produce an executable,
                     32:    this library does not by itself cause the resulting executable
                     33:    to be covered by the GNU General Public License.
                     34:    This exception does not however invalidate any other reasons why
                     35:    the executable file might be covered by the GNU General Public License.  */
                     36: 
                     37: /* Assembler register definitions.  */
                     38: 
                     39: #define A0 r0
                     40: #define A0L r0l
                     41: #define A0H r0h
                     42: 
                     43: #define A1 r1
                     44: #define A1L r1l
                     45: #define A1H r1h
                     46: 
                     47: #define A2 r2
                     48: #define A2L r2l
                     49: #define A2H r2h
                     50: 
                     51: #define A3 r3
                     52: #define A3L r3l
                     53: #define A3H r3h
                     54: 
                     55: #define S0 r4
                     56: #define S0L r4l
                     57: #define S0H r4h
                     58: 
                     59: #define S1 r5
                     60: #define S1L r5l
                     61: #define S1H r5h
                     62: 
                     63: #define S2 r6
                     64: #define S2L r6l
                     65: #define S2H r6h
                     66: 
                     67: #ifdef __H8300__
                     68: #define MOVP   mov.w   /* pointers are 16 bits */
                     69: #define ADDP   add.w
                     70: #define CMPP   cmp.w
                     71: #define PUSHP  push
                     72: #define POPP   pop
                     73: 
                     74: #define A0P    r0
                     75: #define A1P    r1
                     76: #define A2P    r2
                     77: #define A3P    r3
                     78: #define S0P    r4
                     79: #define S1P    r5
                     80: #define S2P    r6
                     81: #endif
                     82: 
                     83: #ifdef __H8300H__
                     84: #define MOVP   mov.l   /* pointers are 32 bits */
                     85: #define ADDP   add.l
                     86: #define CMPP   cmp.l
                     87: #define PUSHP  push.l
                     88: #define POPP   pop.l
                     89: 
                     90: #define A0P    er0
                     91: #define A1P    er1
                     92: #define A2P    er2
                     93: #define A3P    er3
                     94: #define S0P    er4
                     95: #define S1P    er5
                     96: #define S2P    er6
                     97: 
                     98: #define A0E    e0
                     99: #define A1E    e1
                    100: #define A2E    e2
                    101: #define A3E    e3
                    102: #endif
                    103: 
                    104: #ifdef L_cmpsi2
                    105: #ifdef __H8300__
                    106:        .section .text
                    107:        .align 2
                    108:        .global ___cmpsi2
                    109: ___cmpsi2:
                    110:        cmp.w   A2,A0
                    111:        bne     .L2
                    112:        cmp.w   A3,A1
                    113:        bne     .L2
                    114:        mov.w   #1,A0
                    115:        rts
                    116: .L2:
                    117:        cmp.w   A0,A2
                    118:        bgt     .L4
                    119:        bne     .L3
                    120:        cmp.w   A1,A3
                    121:        bls     .L3
                    122: .L4:
                    123:        sub.w   A0,A0
                    124:        rts
                    125: .L3:
                    126:        mov.w   #2,A0
                    127: .L5:
                    128:        rts
                    129:        .end
                    130: #endif
                    131: #endif /* L_cmpsi2 */
                    132: 
                    133: #ifdef L_ucmpsi2
                    134: #ifdef __H8300__
                    135:        .section .text
                    136:        .align 2
                    137:        .global ___ucmpsi2
                    138: ___ucmpsi2:
                    139:        cmp.w   A2,A0
                    140:        bne     .L2
                    141:        cmp.w   A3,A1
                    142:        bne     .L2
                    143:        mov.w   #1,A0
                    144:        rts
                    145: .L2:
                    146:        cmp.w   A0,A2
                    147:        bhi     .L4
                    148:        bne     .L3
                    149:        cmp.w   A1,A3
                    150:        bls     .L3
                    151: .L4:
                    152:        sub.w   A0,A0
                    153:        rts
                    154: .L3:
                    155:        mov.w   #2,A0
                    156: .L5:
                    157:        rts
                    158:        .end
                    159: #endif
                    160: #endif /* L_ucmpsi2 */
                    161: 
                    162: #ifdef L_divhi3
                    163: 
                    164: ;; HImode divides for the H8/300.
                    165: ;; We bunch all of this into one object file since there are several
                    166: ;; "supporting routines".
                    167: 
                    168: ; general purpose normalize routine
                    169: ; 
                    170: ; divisor in A0
                    171: ; dividend in A1
                    172: ; turns both into +ve numbers, and leaves what the answer sign
                    173: ; should be in A2L
                    174: 
                    175: #ifdef __H8300__
                    176:        .section .text
                    177:        .align 2
                    178: divnorm:
                    179:        mov.b   #0x0,A2L
                    180:        or      A0H,A0H         ; is divisor > 0
                    181:        bge     _lab1                   
                    182:        not     A0H             ; no - then make it +ve
                    183:        not     A0L
                    184:        adds    #1,A0                   
                    185:        xor     #0x1,A2L        ; and remember that in A2L
                    186: _lab1: or      A1H,A1H ; look at dividend
                    187:        bge     _lab2           
                    188:        not     A1H             ; it is -ve, make it positive
                    189:        not     A1L
                    190:        adds    #1,A1
                    191:        xor     #0x1,A2L; and toggle sign of result
                    192: _lab2: rts
                    193: 
                    194: ; A0=A0/A1 signed
                    195: 
                    196:        .global ___divhi3
                    197: ___divhi3:
                    198:        bsr     divnorm
                    199:        bsr     ___udivhi3
                    200: negans:        or      A2L,A2L ; should answer be negative ?
                    201:        beq     _lab4
                    202:        not     A0H     ; yes, so make it so
                    203:        not     A0L
                    204:        adds    #1,A0
                    205: _lab4: rts     
                    206: 
                    207: ; A0=A0%A1 signed
                    208: 
                    209:        .global ___modhi3
                    210: ___modhi3:
                    211:        bsr     divnorm
                    212:        bsr     ___udivhi3
                    213:        mov     A3,A0
                    214:        bra     negans
                    215: 
                    216: ; A0=A0%A1 unsigned
                    217: 
                    218:        .global ___umodhi3
                    219: ___umodhi3:
                    220:        bsr     ___udivhi3
                    221:        mov     A3,A0
                    222:        rts
                    223: 
                    224: ; A0=A0/A1 unsigned
                    225: ; A3=A0%A1 unsigned
                    226: ; A2H trashed
                    227: ; D high 8 bits of denom
                    228: ; d low 8 bits of denom
                    229: ; N high 8 bits of num
                    230: ; n low 8 bits of num
                    231: ; M high 8 bits of mod
                    232: ; m low 8 bits of mod
                    233: ; Q high 8 bits of quot
                    234: ; q low 8 bits of quot
                    235: ; P preserve
                    236: 
                    237: ; The h8 only has a 16/8 bit divide, so we look at the incoming and
                    238: ; see how to partition up the expression.
                    239: 
                    240:        .global ___udivhi3
                    241: ___udivhi3:
                    242:                                ; A0 A1 A2 A3 
                    243:                                ; Nn Dd       P
                    244:        sub.w   A3,A3           ; Nn Dd xP 00 
                    245:        or      A1H,A1H          
                    246:        bne     divlongway
                    247:        or      A0H,A0H         
                    248:        beq     _lab6           
                    249: 
                    250: ; we know that D == 0 and N is != 0
                    251:        mov.b   A0H,A3L         ; Nn Dd xP 0N
                    252:        divxu   A1L,A3          ;          MQ
                    253:        mov.b   A3L,A0H         ; Q
                    254: ; dealt with N, do n
                    255: _lab6: mov.b   A0L,A3L         ;           n
                    256:        divxu   A1L,A3          ;          mq
                    257:        mov.b   A3L,A0L         ; Qq
                    258:        mov.b   A3H,A3L         ;           m
                    259:        mov.b   #0x0,A3H        ; Qq       0m
                    260:        rts     
                    261: 
                    262: ; D != 0 - which means the denominator is
                    263: ;          loop around to get the result.
                    264: 
                    265: divlongway:
                    266:        mov.b   A0H,A3L         ; Nn Dd xP 0N
                    267:        mov.b   #0x0,A0H        ; high byte of answer has to be zero
                    268:        mov.b   #0x8,A2H        ;       8
                    269: div8:  add.b   A0L,A0L         ; n*=2
                    270:        rotxl   A3L             ; Make remainder bigger
                    271:        rotxl   A3H             
                    272:        sub.w   A1,A3           ; Q-=N
                    273:        bhs     setbit          ; set a bit ?
                    274:        add.w   A1,A3           ;  no : too far , Q+=N
                    275: 
                    276:        dec     A2H             
                    277:        bne     div8            ; next bit      
                    278:        rts     
                    279: 
                    280: setbit:        inc     A0L             ; do insert bit
                    281:        dec     A2H             
                    282:        bne     div8            ; next bit      
                    283:        rts     
                    284: 
                    285: #endif /* __H8300__ */
                    286: #endif /* L_divhi3 */
                    287: 
                    288: #ifdef L_divsi3
                    289: 
                    290: ;; 4 byte integer divides for the H8/300.
                    291: ;;
                    292: ;; We have one routine which does all the work and lots of 
                    293: ;; little ones which prepare the args and massage the sign.
                    294: ;; We bunch all of this into one object file since there are several
                    295: ;; "supporting routines".
                    296: 
                    297: #ifdef __H8300H__
                    298:        .h8300h
                    299: #endif
                    300: 
                    301:        .section .text
                    302:        .align 2
                    303: 
                    304: ; Put abs SIs into r0/r1 and r2/r3, and leave a 1 in r6l with sign of rest.
                    305: ; This function is here to keep branch displacements small.
                    306: 
                    307: #ifdef __H8300__
                    308: 
                    309: divnorm:
                    310:        mov.b   #0,S2L          ; keep the sign in S2
                    311:        mov.b   A0H,A0H         ; is the numerator -ve
                    312:        bge     postive
                    313: 
                    314:        ; negate arg
                    315:        not     A0H
                    316:        not     A1H
                    317:        not     A0L
                    318:        not     A1L
                    319: 
                    320:        add     #1,A1L
                    321:        addx    #0,A1H
                    322:        addx    #0,A0H
                    323:        addx    #0,A0L
                    324: 
                    325:        mov.b   #1,S2L          ; the sign will be -ve
                    326: postive:
                    327:        mov.b   A2H,A2H         ; is the denominator -ve
                    328:        bge     postive2
                    329:        not     A2L             
                    330:        not     A2H
                    331:        not     A3L
                    332:        not     A3H
                    333:        add.b   #1,A3L  
                    334:        addx    #0,A3H
                    335:        addx    #0,A2L
                    336:        addx    #0,A2H
                    337:        xor     #1,S2L          ; toggle result sign
                    338: postive2:
                    339:        rts
                    340: 
                    341: #else /* __H8300H__ */
                    342: 
                    343: divnorm:
                    344:        mov.b   #0,S2L          ; keep the sign in S2
                    345:        mov.l   A0P,A0P         ; is the numerator -ve
                    346:        bge     postive
                    347: 
                    348:        neg.l   A0P             ; negate arg
                    349:        mov.b   #1,S2L          ; the sign will be -ve
                    350: 
                    351: postive:
                    352:        mov.l   A1P,A1P         ; is the denominator -ve
                    353:        bge     postive2
                    354: 
                    355:        neg.l   A1P             ; negate arg
                    356:        xor.b   #1,S2L          ; toggle result sign
                    357: 
                    358: postive2:
                    359:        rts
                    360: 
                    361: #endif
                    362: 
                    363: ; numerator in A0/A1
                    364: ; denominator in A2/A3
                    365:        .global ___modsi3
                    366: ___modsi3:
                    367:        PUSHP   S2P             
                    368:        PUSHP   S0P
                    369:        PUSHP   S1P
                    370: 
                    371:        bsr     divnorm
                    372:        bsr     divmodsi4
                    373: #ifdef __H8300__
                    374:        mov     S0,A0
                    375:        mov     S1,A1
                    376: #else
                    377:        mov.l   S0P,A0P
                    378: #endif
                    379:        bra     exitdiv
                    380: 
                    381:        .global ___udivsi3
                    382: ___udivsi3:
                    383:        PUSHP   S2P
                    384:        PUSHP   S0P
                    385:        PUSHP   S1P
                    386:        mov.b   #0,S2L  ; keep sign low
                    387:        bsr     divmodsi4
                    388:        bra     exitdiv
                    389: 
                    390:        .global ___umodsi3
                    391: ___umodsi3:
                    392:        PUSHP   S2P
                    393:        PUSHP   S0P
                    394:        PUSHP   S1P
                    395:        mov.b   #0,S2L  ; keep sign low
                    396:        bsr     divmodsi4
                    397: #ifdef __H8300__
                    398:        mov     S0,A0
                    399:        mov     S1,A1
                    400: #else
                    401:        mov.l   S0P,A0P
                    402: #endif
                    403:        bra     exitdiv
                    404:        
                    405:        .global ___divsi3
                    406: ___divsi3:
                    407:        PUSHP   S2P
                    408:        PUSHP   S0P
                    409:        PUSHP   S1P
                    410:        jsr     divnorm
                    411:        jsr     divmodsi4
                    412: 
                    413:        ; examine what the sign should be
                    414: exitdiv:
                    415:        POPP    S1P
                    416:        POPP    S0P
                    417: 
                    418:        or      S2L,S2L
                    419:        beq     reti
                    420:        
                    421:        ; should be -ve
                    422: #ifdef __H8300__
                    423:        not     A0H
                    424:        not     A1H
                    425:        not     A0L
                    426:        not     A1L
                    427: 
                    428:        add     #1,A1L
                    429:        addx    #0,A1H
                    430:        addx    #0,A0H
                    431:        addx    #0,A0L
                    432: #else /* __H8300H__ */
                    433:        neg.l   A0P
                    434: #endif
                    435: 
                    436: reti:
                    437:        POPP    S2P
                    438:        rts     
                    439: 
                    440:        ; takes A0/A1 numerator (A0P for 300h)
                    441:        ; A2/A3 denominator (A1P for 300h)
                    442:        ; returns A0/A1 quotient (A0P for 300h)
                    443:        ; S0/S1 remainder (S0P for 300h)
                    444:        ; trashes S2
                    445: 
                    446: #ifdef __H8300__
                    447: 
                    448: divmodsi4:
                    449:         sub.w  S0,S0           ; zero play area
                    450:         mov.w  S0,S1
                    451:         mov.b  A2H,S2H
                    452:         or     A2L,S2H
                    453:         or     A3H,S2H
                    454:         bne    DenHighZero
                    455:         mov.b  A0H,A0H
                    456:         bne    NumByte0Zero
                    457:         mov.b  A0L,A0L
                    458:         bne    NumByte1Zero
                    459:         mov.b  A1H,A1H
                    460:         bne    NumByte2Zero
                    461:         bra    NumByte3Zero
                    462: NumByte0Zero:
                    463:        mov.b   A0H,S1L
                    464:         divxu  A3L,S1
                    465:         mov.b  S1L,A0H
                    466: NumByte1Zero:
                    467:        mov.b   A0L,S1L
                    468:         divxu  A3L,S1
                    469:         mov.b  S1L,A0L
                    470: NumByte2Zero:
                    471:        mov.b   A1H,S1L
                    472:         divxu  A3L,S1
                    473:         mov.b  S1L,A1H
                    474: NumByte3Zero:
                    475:        mov.b   A1L,S1L
                    476:         divxu  A3L,S1
                    477:         mov.b  S1L,A1L
                    478: 
                    479:         mov.b  S1H,S1L
                    480:         mov.b  #0x0,S1H
                    481:         rts    
                    482: 
                    483: ; have to do the divide by shift and test
                    484: DenHighZero:
                    485:        mov.b   A0H,S1L
                    486:         mov.b  A0L,A0H
                    487:         mov.b  A1H,A0L
                    488:         mov.b  A1L,A1H
                    489: 
                    490:         mov.b  #0,A1L
                    491:         mov.b  #24,S2H ; only do 24 iterations
                    492: 
                    493: nextbit:
                    494:        add.w   A1,A1   ; double the answer guess
                    495:         rotxl  A0L
                    496:         rotxl  A0H
                    497: 
                    498:         rotxl  S1L     ; double remainder
                    499:         rotxl  S1H
                    500:         rotxl  S0L
                    501:         rotxl  S0H
                    502:         sub.w  A3,S1   ; does it all fit
                    503:         subx   A2L,S0L
                    504:         subx   A2H,S0H
                    505:         bhs    setone   
                    506: 
                    507:         add.w  A3,S1   ; no, restore mistake
                    508:         addx   A2L,S0L
                    509:         addx   A2H,S0H
                    510: 
                    511:         dec    S2H
                    512:         bne    nextbit
                    513:         rts    
                    514:        
                    515: setone:
                    516:        inc     A1L
                    517:         dec    S2H
                    518:         bne    nextbit
                    519:         rts    
                    520: 
                    521: #else /* __H8300H__ */
                    522: 
                    523: divmodsi4:
                    524:        sub.l   S0P,S0P         ; zero play area
                    525:        mov.w   A1E,A1E         ; denominator top word 0?
                    526:        bne     DenHighZero
                    527: 
                    528:        ; do it the easy way, see page 107 in manual
                    529:        mov.w   A0E,A2
                    530:        extu.l  A2P
                    531:        divxu.w A1,A2P
                    532:        mov.w   A2E,A0E
                    533:        divxu.w A1,A0P
                    534:        mov.w   A0E,S0
                    535:        mov.w   A2,A0E
                    536:        extu.l  S0P
                    537:        rts
                    538: 
                    539: DenHighZero:
                    540:        mov.w   A0E,A2
                    541:        mov.b   A2H,S0L
                    542:        mov.b   A2L,A2H
                    543:        mov.b   A0H,A2L
                    544:        mov.w   A2,A0E
                    545:        mov.b   A0L,A0H
                    546:        mov.b   #0,A0L
                    547:        mov.b   #24,S2H         ; only do 24 iterations
                    548: 
                    549: nextbit:
                    550:        shll.l  A0P             ; double the answer guess
                    551:        rotxl.l S0P             ; double remainder
                    552:        sub.l   A1P,S0P         ; does it all fit?
                    553:        bhs     setone
                    554: 
                    555:        add.l   A1P,S0P         ; no, restore mistake
                    556:        dec     S2H
                    557:        bne     nextbit
                    558:        rts
                    559: 
                    560: setone:
                    561:        inc     A0L
                    562:        dec     S2H
                    563:        bne     nextbit
                    564:        rts
                    565: 
                    566: #endif
                    567: #endif /* L_divsi3 */
                    568: 
                    569: #ifdef L_mulhi3
                    570: 
                    571: ;; HImode multiply.
                    572: ; The h8 only has an 8*8->16 multiply.
                    573: ; The answer is the same as:
                    574: ; 
                    575: ; product = (srca.l * srcb.l) + ((srca.h * srcb.l) + (srcb.h * srca.l)) * 256
                    576: ; (we can ignore A1.h * A0.h cause that will all off the top)
                    577: ; A0 in
                    578: ; A1 in 
                    579: ; A0 answer
                    580: 
                    581: #ifdef __H8300__
                    582:        .section .text
                    583:        .align 2
                    584:        .global ___mulhi3
                    585: ___mulhi3:
                    586:        mov.b   A1L,A2L         ; A2l gets srcb.l
                    587:        mulxu   A0L,A2          ; A2 gets first sub product 
                    588: 
                    589:        mov.b   A0H,A3L         ; prepare for
                    590:        mulxu   A1L,A3          ; second sub product
                    591: 
                    592:        add.b   A3L,A2H         ; sum first two terms
                    593: 
                    594:        mov.b   A1H,A3L         ; third sub product
                    595:        mulxu   A0L,A3          
                    596: 
                    597:        add.b   A3L,A2H         ; almost there
                    598:        mov.w   A2,A0           ; that is
                    599:        rts
                    600: 
                    601: #endif
                    602: #endif /* L_mulhi3 */
                    603: 
                    604: #ifdef L_mulsi3
                    605: 
                    606: ;; SImode multiply.
                    607: ;; 
                    608: ;; I think that shift and add may be sufficient for this.  Using the
                    609: ;; supplied 8x8->16 would need 10 ops of 14 cycles each + overhead.  This way
                    610: ;; the inner loop uses maybe 20 cycles + overhead, but terminates
                    611: ;; quickly on small args.
                    612: ;;
                    613: ;; A0/A1 src_a
                    614: ;; A2/A3 src_b
                    615: ;;
                    616: ;;  while (a) 
                    617: ;;    {
                    618: ;;      if (a & 1)
                    619: ;;        r += b;
                    620: ;;      a >>= 1;
                    621: ;;      b <<= 1;
                    622: ;;    }
                    623: 
                    624:        .section .text
                    625:        .align 2
                    626: 
                    627: #ifdef __H8300__
                    628: 
                    629:        .global ___mulsi3
                    630: ___mulsi3:
                    631:        PUSHP   S0P
                    632:        PUSHP   S1P
                    633:        PUSHP   S2P
                    634:        
                    635:        sub.w   S0,S0
                    636:        sub.w   S1,S1
                    637:        
                    638:        ; while (a)
                    639: _top:  mov.w   A0,A0
                    640:        bne     _more
                    641:        mov.w   A1,A1
                    642:        beq     _done
                    643: _more: ; if (a & 1)
                    644:        bld     #0,A1L
                    645:        bcc     _nobit
                    646:        ; r += b
                    647:        add.w   A3,S1
                    648:        addx    A2L,S0L
                    649:        addx    A2H,S0H
                    650: _nobit:
                    651:        ; a >>= 1
                    652:        shlr    A0H
                    653:        rotxr   A0L
                    654:        rotxr   A1H
                    655:        rotxr   A1L
                    656:        
                    657:        ; b <<= 1
                    658:        add.w   A3,A3
                    659:        addx    A2L,A2L
                    660:        addx    A2H,A2H
                    661:        bra     _top
                    662: 
                    663: _done:
                    664:        mov.w   S0,A0   
                    665:        mov.w   S1,A1
                    666:        POPP    S2P
                    667:        POPP    S1P
                    668:        POPP    S0P
                    669:        rts
                    670: 
                    671: #else /* __H8300H__ */
                    672: 
                    673:        .h8300h
                    674: 
                    675:        .global ___mulsi3
                    676: ___mulsi3:
                    677:        sub.l   A2P,A2P
                    678: 
                    679:        ; while (a)
                    680: _top:  mov.l   A0P,A0P
                    681:        beq     _done
                    682: 
                    683:        ; if (a & 1)
                    684:        bld     #0,A0L
                    685:        bcc     _nobit
                    686: 
                    687:        ; r += b
                    688:        add.l   A1P,A2P
                    689: 
                    690: _nobit:
                    691:        ; a >>= 1
                    692:        shlr.l  A0P
                    693: 
                    694:        ; b <<= 1
                    695:        shll.l  A1P
                    696:        bra     _top
                    697: 
                    698: _done:
                    699:        mov.l   A2P,A0P
                    700:        rts
                    701: 
                    702: #endif
                    703: #endif /* L_mulsi3 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.