Back to home page

LXR

 
 

    


0001 /* head.S: kernel entry point for FR-V kernel
0002  *
0003  * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.
0004  * Written by David Howells (dhowells@redhat.com)
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License
0008  * as published by the Free Software Foundation; either version
0009  * 2 of the License, or (at your option) any later version.
0010  */
0011 
0012 #include <linux/init.h>
0013 #include <linux/threads.h>
0014 #include <linux/linkage.h>
0015 #include <asm/thread_info.h>
0016 #include <asm/ptrace.h>
0017 #include <asm/page.h>
0018 #include <asm/spr-regs.h>
0019 #include <asm/mb86943a.h>
0020 #include <asm/cache.h>
0021 #include "head.inc"
0022 
0023 ###############################################################################
0024 #
0025 # void _boot(unsigned long magic, char *command_line) __attribute__((noreturn))
0026 #
0027 # - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel
0028 #   command line string
0029 #
0030 ###############################################################################
0031     __HEAD
0032     .balign     4
0033 
0034     .globl      _boot, __head_reference
0035         .type       _boot,@function
0036 _boot:
0037 __head_reference:
0038     sethi.p     %hi(LED_ADDR),gr30
0039     setlo       %lo(LED_ADDR),gr30
0040 
0041     LEDS        0x0000
0042 
0043     # calculate reference address for PC-relative stuff
0044     call        0f
0045 0:  movsg       lr,gr26
0046     addi        gr26,#__head_reference-0b,gr26
0047 
0048     # invalidate and disable both of the caches and turn off the memory access checking
0049     dcef        @(gr0,gr0),1
0050     bar
0051 
0052     sethi.p     %hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
0053     setlo       %lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
0054     movsg       hsr0,gr5
0055     and     gr4,gr5,gr5
0056     movgs       gr5,hsr0
0057     movsg       hsr0,gr5
0058 
0059     LEDS        0x0001
0060 
0061     icei        @(gr0,gr0),1
0062     dcei        @(gr0,gr0),1
0063     bar
0064 
0065     # turn the instruction cache back on
0066     sethi.p     %hi(HSR0_ICE),gr4
0067     setlo       %lo(HSR0_ICE),gr4
0068     movsg       hsr0,gr5
0069     or      gr4,gr5,gr5
0070     movgs       gr5,hsr0
0071     movsg       hsr0,gr5
0072 
0073     bar
0074 
0075     LEDS        0x0002
0076 
0077     # retrieve the parameters (including command line) before we overwrite them
0078     sethi.p     %hi(0xdead1eaf),gr7
0079     setlo       %lo(0xdead1eaf),gr7
0080     subcc       gr7,gr8,gr0,icc0
0081     bne     icc0,#0,__head_no_parameters
0082 
0083     sethi.p     %hi(redboot_command_line-1),gr6
0084     setlo       %lo(redboot_command_line-1),gr6
0085     sethi.p     %hi(__head_reference),gr4
0086     setlo       %lo(__head_reference),gr4
0087     sub     gr6,gr4,gr6
0088     add.p       gr6,gr26,gr6
0089     subi        gr9,#1,gr9
0090     setlos.p    #511,gr4
0091     setlos      #1,gr5
0092 
0093 __head_copy_cmdline:
0094     ldubu.p     @(gr9,gr5),gr16
0095     subicc      gr4,#1,gr4,icc0
0096     stbu.p      gr16,@(gr6,gr5)
0097     subicc      gr16,#0,gr0,icc1
0098     bls     icc0,#0,__head_end_cmdline
0099     bne     icc1,#1,__head_copy_cmdline
0100 __head_end_cmdline:
0101     stbu        gr0,@(gr6,gr5)
0102 __head_no_parameters:
0103 
0104 ###############################################################################
0105 #
0106 # we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux)
0107 # - note that we're going to have to run entirely out of the icache whilst
0108 #   fiddling with the SDRAM controller registers
0109 #
0110 ###############################################################################
0111 #ifdef CONFIG_MMU
0112     call        __head_fr451_describe_sdram
0113 
0114 #else
0115     movsg       psr,gr5
0116     srli        gr5,#28,gr5
0117     subicc      gr5,#3,gr0,icc0
0118     beq     icc0,#0,__head_fr551_sdram
0119 
0120     call        __head_fr401_describe_sdram
0121     bra     __head_do_sdram
0122 
0123 __head_fr551_sdram:
0124     call        __head_fr555_describe_sdram
0125     LEDS        0x000d
0126 
0127 __head_do_sdram:
0128 #endif
0129 
0130     # preload the registers with invalid values in case any DBR/DARS are marked not present
0131     sethi.p     %hi(0xfe000000),gr17        ; unused SDRAM DBR value
0132     setlo       %lo(0xfe000000),gr17
0133     or.p        gr17,gr0,gr20
0134     or      gr17,gr0,gr21
0135     or.p        gr17,gr0,gr22
0136     or      gr17,gr0,gr23
0137 
0138     # consult the SDRAM controller CS address registers
0139     cld     @(gr14,gr0 ),gr20,  cc0,#1  ; DBR0 / DARS0
0140     cld     @(gr14,gr11),gr21,  cc1,#1  ; DBR1 / DARS1
0141     cld     @(gr14,gr12),gr22,  cc2,#1  ; DBR2 / DARS2
0142     cld.p       @(gr14,gr13),gr23,  cc3,#1  ; DBR3 / DARS3
0143 
0144     sll     gr20,gr15,gr20          ; shift values up for FR551
0145     sll     gr21,gr15,gr21
0146     sll     gr22,gr15,gr22
0147     sll     gr23,gr15,gr23
0148 
0149     LEDS        0x0003
0150 
0151     # assume the lowest valid CS line to be the SDRAM base and get its address
0152     subcc       gr20,gr17,gr0,icc0
0153     subcc.p     gr21,gr17,gr0,icc1
0154     subcc       gr22,gr17,gr0,icc2
0155     subcc.p     gr23,gr17,gr0,icc3
0156     ckne        icc0,cc4            ; T if DBR0 != 0xfe000000
0157     ckne        icc1,cc5
0158     ckne        icc2,cc6
0159     ckne        icc3,cc7
0160     cor     gr23,gr0,gr24,      cc7,#1  ; GR24 = SDRAM base
0161     cor     gr22,gr0,gr24,      cc6,#1
0162     cor     gr21,gr0,gr24,      cc5,#1
0163     cor     gr20,gr0,gr24,      cc4,#1
0164 
0165     # calculate the displacement required to get the SDRAM into the right place in memory
0166     sethi.p     %hi(__sdram_base),gr16
0167     setlo       %lo(__sdram_base),gr16
0168     sub     gr16,gr24,gr16          ; delta = __sdram_base - DBRx
0169 
0170     # calculate the new values to go in the controller regs
0171     cadd.p      gr20,gr16,gr20,     cc4,#1  ; DCS#0 (new) = DCS#0 (old) + delta
0172     cadd        gr21,gr16,gr21,     cc5,#1
0173     cadd.p      gr22,gr16,gr22,     cc6,#1
0174     cadd        gr23,gr16,gr23,     cc7,#1
0175 
0176     srl     gr20,gr15,gr20          ; shift values down for FR551
0177     srl     gr21,gr15,gr21
0178     srl     gr22,gr15,gr22
0179     srl     gr23,gr15,gr23
0180 
0181     # work out the address at which the reg updater resides and lock it into icache
0182     # also work out the address the updater will jump to when finished
0183     sethi.p     %hi(__head_move_sdram-__head_reference),gr18
0184     setlo       %lo(__head_move_sdram-__head_reference),gr18
0185     sethi.p     %hi(__head_sdram_moved-__head_reference),gr19
0186     setlo       %lo(__head_sdram_moved-__head_reference),gr19
0187     add.p       gr18,gr26,gr18
0188     add     gr19,gr26,gr19
0189     add.p       gr19,gr16,gr19          ; moved = addr + (__sdram_base - DBRx)
0190     add     gr18,gr5,gr4            ; two cachelines probably required
0191 
0192     icpl        gr18,gr0,#1         ; load and lock the cachelines
0193     icpl        gr4,gr0,#1
0194     LEDS        0x0004
0195     membar
0196     bar
0197     jmpl        @(gr18,gr0)
0198 
0199     .balign     L1_CACHE_BYTES
0200 __head_move_sdram:
0201     cst     gr20,@(gr14,gr0 ),  cc4,#1
0202     cst     gr21,@(gr14,gr11),  cc5,#1
0203     cst     gr22,@(gr14,gr12),  cc6,#1
0204     cst     gr23,@(gr14,gr13),  cc7,#1
0205     cld     @(gr14,gr0 ),gr20,  cc4,#1
0206     cld     @(gr14,gr11),gr21,  cc5,#1
0207     cld     @(gr14,gr12),gr22,  cc4,#1
0208     cld     @(gr14,gr13),gr23,  cc7,#1
0209     bar
0210     membar
0211     jmpl        @(gr19,gr0)
0212 
0213     .balign     L1_CACHE_BYTES
0214 __head_sdram_moved:
0215     icul        gr18
0216     add     gr18,gr5,gr4
0217     icul        gr4
0218     icei        @(gr0,gr0),1
0219     dcei        @(gr0,gr0),1
0220 
0221     LEDS        0x0005
0222 
0223     # recalculate reference address
0224     call        0f
0225 0:  movsg       lr,gr26
0226     addi        gr26,#__head_reference-0b,gr26
0227 
0228 
0229 ###############################################################################
0230 #
0231 # move the kernel image down to the bottom of the SDRAM
0232 #
0233 ###############################################################################
0234     sethi.p     %hi(__kernel_image_size_no_bss+15),gr4
0235     setlo       %lo(__kernel_image_size_no_bss+15),gr4
0236     srli.p      gr4,#4,gr4          ; count
0237     or      gr26,gr26,gr16          ; source
0238 
0239     sethi.p     %hi(__sdram_base),gr17      ; destination
0240     setlo       %lo(__sdram_base),gr17
0241 
0242     setlos      #8,gr5
0243     sub.p       gr16,gr5,gr16           ; adjust src for LDDU
0244     sub     gr17,gr5,gr17           ; adjust dst for LDDU
0245 
0246     sethi.p     %hi(__head_move_kernel-__head_reference),gr18
0247     setlo       %lo(__head_move_kernel-__head_reference),gr18
0248     sethi.p     %hi(__head_kernel_moved-__head_reference+__sdram_base),gr19
0249     setlo       %lo(__head_kernel_moved-__head_reference+__sdram_base),gr19
0250     add     gr18,gr26,gr18
0251     icpl        gr18,gr0,#1
0252     jmpl        @(gr18,gr0)
0253 
0254     .balign     32
0255 __head_move_kernel:
0256     lddu        @(gr16,gr5),gr10
0257     lddu        @(gr16,gr5),gr12
0258     stdu.p      gr10,@(gr17,gr5)
0259     subicc      gr4,#1,gr4,icc0
0260     stdu.p      gr12,@(gr17,gr5)
0261     bhi     icc0,#0,__head_move_kernel
0262     jmpl        @(gr19,gr0)
0263 
0264     .balign     32
0265 __head_kernel_moved:
0266     icul        gr18
0267     icei        @(gr0,gr0),1
0268     dcei        @(gr0,gr0),1
0269 
0270     LEDS        0x0006
0271 
0272     # recalculate reference address
0273     call        0f
0274 0:  movsg       lr,gr26
0275     addi        gr26,#__head_reference-0b,gr26
0276 
0277 
0278 ###############################################################################
0279 #
0280 # rearrange the iomem map and set the protection registers
0281 #
0282 ###############################################################################
0283 
0284 #ifdef CONFIG_MMU
0285     LEDS        0x3301
0286     call        __head_fr451_set_busctl
0287     LEDS        0x3303
0288     call        __head_fr451_survey_sdram
0289     LEDS        0x3305
0290     call        __head_fr451_set_protection
0291 
0292 #else
0293     movsg       psr,gr5
0294     srli        gr5,#PSR_IMPLE_SHIFT,gr5
0295     subicc      gr5,#PSR_IMPLE_FR551,gr0,icc0
0296     beq     icc0,#0,__head_fr555_memmap
0297     subicc      gr5,#PSR_IMPLE_FR451,gr0,icc0
0298     beq     icc0,#0,__head_fr451_memmap
0299 
0300     LEDS        0x3101
0301     call        __head_fr401_set_busctl
0302     LEDS        0x3103
0303     call        __head_fr401_survey_sdram
0304     LEDS        0x3105
0305     call        __head_fr401_set_protection
0306     bra     __head_done_memmap
0307 
0308 __head_fr451_memmap:
0309     LEDS        0x3301
0310     call        __head_fr401_set_busctl
0311     LEDS        0x3303
0312     call        __head_fr401_survey_sdram
0313     LEDS        0x3305
0314     call        __head_fr451_set_protection
0315     bra     __head_done_memmap
0316 
0317 __head_fr555_memmap:
0318     LEDS        0x3501
0319     call        __head_fr555_set_busctl
0320     LEDS        0x3503
0321     call        __head_fr555_survey_sdram
0322     LEDS        0x3505
0323     call        __head_fr555_set_protection
0324 
0325 __head_done_memmap:
0326 #endif
0327     LEDS        0x0007
0328 
0329 ###############################################################################
0330 #
0331 # turn the data cache and MMU on
0332 # - for the FR451 this'll mean that the window through which the kernel is
0333 #   viewed will change
0334 #
0335 ###############################################################################
0336 
0337 #ifdef CONFIG_MMU
0338 #define MMUMODE     HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT
0339 #else
0340 #define MMUMODE     HSR0_EIMMU|HSR0_EDMMU
0341 #endif
0342 
0343     movsg       hsr0,gr5
0344 
0345     sethi.p     %hi(MMUMODE),gr4
0346     setlo       %lo(MMUMODE),gr4
0347     or      gr4,gr5,gr5
0348 
0349 #if defined(CONFIG_FRV_DEFL_CACHE_WTHRU)
0350     sethi.p     %hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
0351     setlo       %lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
0352 #elif defined(CONFIG_FRV_DEFL_CACHE_WBACK)
0353     sethi.p     %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
0354     setlo       %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
0355 #elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND)
0356     sethi.p     %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
0357     setlo       %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
0358 
0359     movsg       psr,gr6
0360     srli        gr6,#24,gr6
0361     cmpi        gr6,#0x50,icc0      // FR451
0362     beq     icc0,#0,0f
0363     cmpi        gr6,#0x40,icc0      // FR405
0364     bne     icc0,#0,1f
0365 0:
0366     # turn off write-allocate
0367     sethi.p     %hi(HSR0_NWA),gr6
0368     setlo       %lo(HSR0_NWA),gr6
0369     or      gr4,gr6,gr4
0370 1:
0371 
0372 #else
0373 #error No default cache configuration set
0374 #endif
0375 
0376     or      gr4,gr5,gr5
0377     movgs       gr5,hsr0
0378     bar
0379 
0380     LEDS        0x0008
0381 
0382     sethi.p     %hi(__head_mmu_enabled),gr19
0383     setlo       %lo(__head_mmu_enabled),gr19
0384     jmpl        @(gr19,gr0)
0385 
0386 __head_mmu_enabled:
0387     icei        @(gr0,gr0),#1
0388     dcei        @(gr0,gr0),#1
0389 
0390     LEDS        0x0009
0391 
0392 #ifdef CONFIG_MMU
0393     call        __head_fr451_finalise_protection
0394 #endif
0395 
0396     LEDS        0x000a
0397 
0398 ###############################################################################
0399 #
0400 # set up the runtime environment
0401 #
0402 ###############################################################################
0403 
0404     # clear the BSS area
0405     sethi.p     %hi(__bss_start),gr4
0406     setlo       %lo(__bss_start),gr4
0407     sethi.p     %hi(_end),gr5
0408     setlo       %lo(_end),gr5
0409     or.p        gr0,gr0,gr18
0410     or      gr0,gr0,gr19
0411 
0412 0:
0413     stdi        gr18,@(gr4,#0)
0414     stdi        gr18,@(gr4,#8)
0415     stdi        gr18,@(gr4,#16)
0416     stdi.p      gr18,@(gr4,#24)
0417     addi        gr4,#24,gr4
0418     subcc       gr5,gr4,gr0,icc0
0419     bhi     icc0,#2,0b
0420 
0421     LEDS        0x000b
0422 
0423     # save the SDRAM details
0424     sethi.p     %hi(__sdram_old_base),gr4
0425     setlo       %lo(__sdram_old_base),gr4
0426     st      gr24,@(gr4,gr0)
0427 
0428     sethi.p     %hi(__sdram_base),gr5
0429     setlo       %lo(__sdram_base),gr5
0430     sethi.p     %hi(memory_start),gr4
0431     setlo       %lo(memory_start),gr4
0432     st      gr5,@(gr4,gr0)
0433 
0434     add     gr25,gr5,gr25
0435     sethi.p     %hi(memory_end),gr4
0436     setlo       %lo(memory_end),gr4
0437     st      gr25,@(gr4,gr0)
0438 
0439     # point the TBR at the kernel trap table
0440     sethi.p     %hi(__entry_kerneltrap_table),gr4
0441     setlo       %lo(__entry_kerneltrap_table),gr4
0442     movgs       gr4,tbr
0443 
0444     # set up the exception frame for init
0445     sethi.p     %hi(__kernel_frame0_ptr),gr28
0446     setlo       %lo(__kernel_frame0_ptr),gr28
0447     sethi.p     %hi(_gp),gr16
0448     setlo       %lo(_gp),gr16
0449     sethi.p     %hi(__entry_usertrap_table),gr4
0450     setlo       %lo(__entry_usertrap_table),gr4
0451 
0452     lddi        @(gr28,#0),gr28     ; load __frame & current
0453     ldi.p       @(gr29,#4),gr15     ; set current_thread
0454 
0455     or      gr0,gr0,fp
0456     or      gr28,gr0,sp
0457 
0458     sti.p       gr4,@(gr28,REG_TBR)
0459     setlos      #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
0460     movgs       gr5,isr
0461 
0462     # turn on and off various CPU services
0463     movsg       psr,gr22
0464     sethi.p     %hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
0465     setlo       %lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
0466     or      gr22,gr4,gr22
0467     movgs       gr22,psr
0468 
0469     andi        gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22
0470     ori     gr22,#PSR_ET,gr22
0471     sti     gr22,@(gr28,REG_PSR)
0472 
0473 
0474 ###############################################################################
0475 #
0476 # set up the registers and jump into the kernel
0477 #
0478 ###############################################################################
0479 
0480     LEDS        0x000c
0481 
0482     sethi.p     #0xe5e5,gr3
0483     setlo       #0xe5e5,gr3
0484     or.p        gr3,gr0,gr4
0485     or      gr3,gr0,gr5
0486     or.p        gr3,gr0,gr6
0487     or      gr3,gr0,gr7
0488     or.p        gr3,gr0,gr8
0489     or      gr3,gr0,gr9
0490     or.p        gr3,gr0,gr10
0491     or      gr3,gr0,gr11
0492     or.p        gr3,gr0,gr12
0493     or      gr3,gr0,gr13
0494     or.p        gr3,gr0,gr14
0495     or      gr3,gr0,gr17
0496     or.p        gr3,gr0,gr18
0497     or      gr3,gr0,gr19
0498     or.p        gr3,gr0,gr20
0499     or      gr3,gr0,gr21
0500     or.p        gr3,gr0,gr23
0501     or      gr3,gr0,gr24
0502     or.p        gr3,gr0,gr25
0503     or      gr3,gr0,gr26
0504     or.p        gr3,gr0,gr27
0505 #   or      gr3,gr0,gr30
0506     or      gr3,gr0,gr31
0507     movgs       gr0,lr
0508     movgs       gr0,lcr
0509     movgs       gr0,ccr
0510     movgs       gr0,cccr
0511 
0512     # initialise the virtual interrupt handling
0513     subcc       gr0,gr0,gr0,icc2        /* set Z, clear C */
0514 
0515 #ifdef CONFIG_MMU
0516     movgs       gr3,scr2
0517     movgs       gr3,scr3
0518 #endif
0519 
0520     LEDS        0x0fff
0521 
0522     # invoke the debugging stub if present
0523     # - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c
0524     #   (it will not return here)
0525     break
0526     .globl      __debug_stub_init_break
0527 __debug_stub_init_break:
0528 
0529     # however, if you need to use an ICE, and don't care about using any userspace
0530     # debugging tools (such as the ptrace syscall), you can just step over the break
0531     # above and get to the kernel this way
0532     # look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed
0533     call        start_kernel
0534 
0535     .globl      __head_end
0536 __head_end:
0537     .size       _boot, .-_boot
0538 
0539     # provide a point for GDB to place a break
0540     .section    .text..start,"ax"
0541     .globl      _start
0542     .balign     4
0543 _start:
0544     call        _boot
0545 
0546     .previous
0547 ###############################################################################
0548 #
0549 # split a tile off of the region defined by GR8-GR9
0550 #
0551 #   ENTRY:          EXIT:
0552 # GR4   -           IAMPR value representing tile
0553 # GR5   -           DAMPR value representing tile
0554 # GR6   -           IAMLR value representing tile
0555 # GR7   -           DAMLR value representing tile
0556 # GR8   region base pointer [saved]
0557 # GR9   region top pointer  updated to exclude new tile
0558 # GR11  xAMLR mask      [saved]
0559 # GR25  SDRAM size      [saved]
0560 # GR30  LED address     [saved]
0561 #
0562 # - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling
0563 #
0564 ###############################################################################
0565     .globl      __head_split_region
0566     .type       __head_split_region,@function
0567 __head_split_region:
0568     subcc.p     gr9,gr8,gr4,icc0
0569     setlos      #31,gr5
0570     scan.p      gr4,gr0,gr6
0571     beq     icc0,#0,__head_region_empty
0572     sub.p       gr5,gr6,gr6         ; bit number of highest set bit (1MB=>20)
0573     setlos      #1,gr4
0574     sll.p       gr4,gr6,gr4         ; size of region (1 << bitno)
0575     subi        gr6,#17,gr6         ; 1MB => 0x03
0576     slli.p      gr6,#4,gr6          ; 1MB => 0x30
0577     sub     gr9,gr4,gr9         ; move uncovered top down
0578 
0579     or      gr9,gr6,gr4
0580     ori     gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4
0581     or.p        gr4,gr0,gr5
0582 
0583     and     gr4,gr11,gr6
0584     and.p       gr5,gr11,gr7
0585     bralr
0586 
0587 __head_region_empty:
0588     or.p        gr0,gr0,gr4
0589     or      gr0,gr0,gr5
0590     or.p        gr0,gr0,gr6
0591     or      gr0,gr0,gr7
0592     bralr
0593     .size       __head_split_region, .-__head_split_region
0594 
0595 ###############################################################################
0596 #
0597 # write the 32-bit hex number in GR8 to ttyS0
0598 #
0599 ###############################################################################
0600 #if 0
0601     .globl      __head_write_to_ttyS0
0602     .type       __head_write_to_ttyS0,@function
0603 __head_write_to_ttyS0:
0604     sethi.p     %hi(0xfeff9c00),gr31
0605     setlo       %lo(0xfeff9c00),gr31
0606     setlos      #8,gr20
0607 
0608 0:  ldubi       @(gr31,#5*8),gr21
0609     andi        gr21,#0x60,gr21
0610     subicc      gr21,#0x60,gr21,icc0
0611     bne     icc0,#0,0b
0612 
0613 1:  srli        gr8,#28,gr21
0614     slli        gr8,#4,gr8
0615 
0616     addi        gr21,#'0',gr21
0617     subicc      gr21,#'9',gr0,icc0
0618     bls     icc0,#2,2f
0619     addi        gr21,#'A'-'0'-10,gr21
0620 2:
0621     stbi        gr21,@(gr31,#0*8)
0622     subicc      gr20,#1,gr20,icc0
0623     bhi     icc0,#2,1b
0624 
0625     setlos      #'\r',gr21
0626     stbi        gr21,@(gr31,#0*8)
0627 
0628     setlos      #'\n',gr21
0629     stbi        gr21,@(gr31,#0*8)
0630 
0631 3:  ldubi       @(gr31,#5*8),gr21
0632     andi        gr21,#0x60,gr21
0633     subicc      gr21,#0x60,gr21,icc0
0634     bne     icc0,#0,3b
0635     bralr
0636 
0637     .size       __head_write_to_ttyS0, .-__head_write_to_ttyS0
0638 #endif