head.S 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. /* head.S: kernel entry point for FR-V kernel
  2. *
  3. * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/init.h>
  12. #include <linux/threads.h>
  13. #include <linux/linkage.h>
  14. #include <asm/thread_info.h>
  15. #include <asm/ptrace.h>
  16. #include <asm/page.h>
  17. #include <asm/spr-regs.h>
  18. #include <asm/mb86943a.h>
  19. #include <asm/cache.h>
  20. #include "head.inc"
  21. ###############################################################################
  22. #
  23. # void _boot(unsigned long magic, char *command_line) __attribute__((noreturn))
  24. #
  25. # - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel
  26. # command line string
  27. #
  28. ###############################################################################
  29. __HEAD
  30. .balign 4
  31. .globl _boot, __head_reference
  32. .type _boot,@function
  33. _boot:
  34. __head_reference:
  35. sethi.p %hi(LED_ADDR),gr30
  36. setlo %lo(LED_ADDR),gr30
  37. LEDS 0x0000
  38. # calculate reference address for PC-relative stuff
  39. call 0f
  40. 0: movsg lr,gr26
  41. addi gr26,#__head_reference-0b,gr26
  42. # invalidate and disable both of the caches and turn off the memory access checking
  43. dcef @(gr0,gr0),1
  44. bar
  45. sethi.p %hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
  46. setlo %lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
  47. movsg hsr0,gr5
  48. and gr4,gr5,gr5
  49. movgs gr5,hsr0
  50. movsg hsr0,gr5
  51. LEDS 0x0001
  52. icei @(gr0,gr0),1
  53. dcei @(gr0,gr0),1
  54. bar
  55. # turn the instruction cache back on
  56. sethi.p %hi(HSR0_ICE),gr4
  57. setlo %lo(HSR0_ICE),gr4
  58. movsg hsr0,gr5
  59. or gr4,gr5,gr5
  60. movgs gr5,hsr0
  61. movsg hsr0,gr5
  62. bar
  63. LEDS 0x0002
  64. # retrieve the parameters (including command line) before we overwrite them
  65. sethi.p %hi(0xdead1eaf),gr7
  66. setlo %lo(0xdead1eaf),gr7
  67. subcc gr7,gr8,gr0,icc0
  68. bne icc0,#0,__head_no_parameters
  69. sethi.p %hi(redboot_command_line-1),gr6
  70. setlo %lo(redboot_command_line-1),gr6
  71. sethi.p %hi(__head_reference),gr4
  72. setlo %lo(__head_reference),gr4
  73. sub gr6,gr4,gr6
  74. add.p gr6,gr26,gr6
  75. subi gr9,#1,gr9
  76. setlos.p #511,gr4
  77. setlos #1,gr5
  78. __head_copy_cmdline:
  79. ldubu.p @(gr9,gr5),gr16
  80. subicc gr4,#1,gr4,icc0
  81. stbu.p gr16,@(gr6,gr5)
  82. subicc gr16,#0,gr0,icc1
  83. bls icc0,#0,__head_end_cmdline
  84. bne icc1,#1,__head_copy_cmdline
  85. __head_end_cmdline:
  86. stbu gr0,@(gr6,gr5)
  87. __head_no_parameters:
  88. ###############################################################################
  89. #
  90. # we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux)
  91. # - note that we're going to have to run entirely out of the icache whilst
  92. # fiddling with the SDRAM controller registers
  93. #
  94. ###############################################################################
  95. #ifdef CONFIG_MMU
  96. call __head_fr451_describe_sdram
  97. #else
  98. movsg psr,gr5
  99. srli gr5,#28,gr5
  100. subicc gr5,#3,gr0,icc0
  101. beq icc0,#0,__head_fr551_sdram
  102. call __head_fr401_describe_sdram
  103. bra __head_do_sdram
  104. __head_fr551_sdram:
  105. call __head_fr555_describe_sdram
  106. LEDS 0x000d
  107. __head_do_sdram:
  108. #endif
  109. # preload the registers with invalid values in case any DBR/DARS are marked not present
  110. sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value
  111. setlo %lo(0xfe000000),gr17
  112. or.p gr17,gr0,gr20
  113. or gr17,gr0,gr21
  114. or.p gr17,gr0,gr22
  115. or gr17,gr0,gr23
  116. # consult the SDRAM controller CS address registers
  117. cld @(gr14,gr0 ),gr20, cc0,#1 ; DBR0 / DARS0
  118. cld @(gr14,gr11),gr21, cc1,#1 ; DBR1 / DARS1
  119. cld @(gr14,gr12),gr22, cc2,#1 ; DBR2 / DARS2
  120. cld.p @(gr14,gr13),gr23, cc3,#1 ; DBR3 / DARS3
  121. sll gr20,gr15,gr20 ; shift values up for FR551
  122. sll gr21,gr15,gr21
  123. sll gr22,gr15,gr22
  124. sll gr23,gr15,gr23
  125. LEDS 0x0003
  126. # assume the lowest valid CS line to be the SDRAM base and get its address
  127. subcc gr20,gr17,gr0,icc0
  128. subcc.p gr21,gr17,gr0,icc1
  129. subcc gr22,gr17,gr0,icc2
  130. subcc.p gr23,gr17,gr0,icc3
  131. ckne icc0,cc4 ; T if DBR0 != 0xfe000000
  132. ckne icc1,cc5
  133. ckne icc2,cc6
  134. ckne icc3,cc7
  135. cor gr23,gr0,gr24, cc7,#1 ; GR24 = SDRAM base
  136. cor gr22,gr0,gr24, cc6,#1
  137. cor gr21,gr0,gr24, cc5,#1
  138. cor gr20,gr0,gr24, cc4,#1
  139. # calculate the displacement required to get the SDRAM into the right place in memory
  140. sethi.p %hi(__sdram_base),gr16
  141. setlo %lo(__sdram_base),gr16
  142. sub gr16,gr24,gr16 ; delta = __sdram_base - DBRx
  143. # calculate the new values to go in the controller regs
  144. cadd.p gr20,gr16,gr20, cc4,#1 ; DCS#0 (new) = DCS#0 (old) + delta
  145. cadd gr21,gr16,gr21, cc5,#1
  146. cadd.p gr22,gr16,gr22, cc6,#1
  147. cadd gr23,gr16,gr23, cc7,#1
  148. srl gr20,gr15,gr20 ; shift values down for FR551
  149. srl gr21,gr15,gr21
  150. srl gr22,gr15,gr22
  151. srl gr23,gr15,gr23
  152. # work out the address at which the reg updater resides and lock it into icache
  153. # also work out the address the updater will jump to when finished
  154. sethi.p %hi(__head_move_sdram-__head_reference),gr18
  155. setlo %lo(__head_move_sdram-__head_reference),gr18
  156. sethi.p %hi(__head_sdram_moved-__head_reference),gr19
  157. setlo %lo(__head_sdram_moved-__head_reference),gr19
  158. add.p gr18,gr26,gr18
  159. add gr19,gr26,gr19
  160. add.p gr19,gr16,gr19 ; moved = addr + (__sdram_base - DBRx)
  161. add gr18,gr5,gr4 ; two cachelines probably required
  162. icpl gr18,gr0,#1 ; load and lock the cachelines
  163. icpl gr4,gr0,#1
  164. LEDS 0x0004
  165. membar
  166. bar
  167. jmpl @(gr18,gr0)
  168. .balign L1_CACHE_BYTES
  169. __head_move_sdram:
  170. cst gr20,@(gr14,gr0 ), cc4,#1
  171. cst gr21,@(gr14,gr11), cc5,#1
  172. cst gr22,@(gr14,gr12), cc6,#1
  173. cst gr23,@(gr14,gr13), cc7,#1
  174. cld @(gr14,gr0 ),gr20, cc4,#1
  175. cld @(gr14,gr11),gr21, cc5,#1
  176. cld @(gr14,gr12),gr22, cc4,#1
  177. cld @(gr14,gr13),gr23, cc7,#1
  178. bar
  179. membar
  180. jmpl @(gr19,gr0)
  181. .balign L1_CACHE_BYTES
  182. __head_sdram_moved:
  183. icul gr18
  184. add gr18,gr5,gr4
  185. icul gr4
  186. icei @(gr0,gr0),1
  187. dcei @(gr0,gr0),1
  188. LEDS 0x0005
  189. # recalculate reference address
  190. call 0f
  191. 0: movsg lr,gr26
  192. addi gr26,#__head_reference-0b,gr26
  193. ###############################################################################
  194. #
  195. # move the kernel image down to the bottom of the SDRAM
  196. #
  197. ###############################################################################
  198. sethi.p %hi(__kernel_image_size_no_bss+15),gr4
  199. setlo %lo(__kernel_image_size_no_bss+15),gr4
  200. srli.p gr4,#4,gr4 ; count
  201. or gr26,gr26,gr16 ; source
  202. sethi.p %hi(__sdram_base),gr17 ; destination
  203. setlo %lo(__sdram_base),gr17
  204. setlos #8,gr5
  205. sub.p gr16,gr5,gr16 ; adjust src for LDDU
  206. sub gr17,gr5,gr17 ; adjust dst for LDDU
  207. sethi.p %hi(__head_move_kernel-__head_reference),gr18
  208. setlo %lo(__head_move_kernel-__head_reference),gr18
  209. sethi.p %hi(__head_kernel_moved-__head_reference+__sdram_base),gr19
  210. setlo %lo(__head_kernel_moved-__head_reference+__sdram_base),gr19
  211. add gr18,gr26,gr18
  212. icpl gr18,gr0,#1
  213. jmpl @(gr18,gr0)
  214. .balign 32
  215. __head_move_kernel:
  216. lddu @(gr16,gr5),gr10
  217. lddu @(gr16,gr5),gr12
  218. stdu.p gr10,@(gr17,gr5)
  219. subicc gr4,#1,gr4,icc0
  220. stdu.p gr12,@(gr17,gr5)
  221. bhi icc0,#0,__head_move_kernel
  222. jmpl @(gr19,gr0)
  223. .balign 32
  224. __head_kernel_moved:
  225. icul gr18
  226. icei @(gr0,gr0),1
  227. dcei @(gr0,gr0),1
  228. LEDS 0x0006
  229. # recalculate reference address
  230. call 0f
  231. 0: movsg lr,gr26
  232. addi gr26,#__head_reference-0b,gr26
  233. ###############################################################################
  234. #
  235. # rearrange the iomem map and set the protection registers
  236. #
  237. ###############################################################################
  238. #ifdef CONFIG_MMU
  239. LEDS 0x3301
  240. call __head_fr451_set_busctl
  241. LEDS 0x3303
  242. call __head_fr451_survey_sdram
  243. LEDS 0x3305
  244. call __head_fr451_set_protection
  245. #else
  246. movsg psr,gr5
  247. srli gr5,#PSR_IMPLE_SHIFT,gr5
  248. subicc gr5,#PSR_IMPLE_FR551,gr0,icc0
  249. beq icc0,#0,__head_fr555_memmap
  250. subicc gr5,#PSR_IMPLE_FR451,gr0,icc0
  251. beq icc0,#0,__head_fr451_memmap
  252. LEDS 0x3101
  253. call __head_fr401_set_busctl
  254. LEDS 0x3103
  255. call __head_fr401_survey_sdram
  256. LEDS 0x3105
  257. call __head_fr401_set_protection
  258. bra __head_done_memmap
  259. __head_fr451_memmap:
  260. LEDS 0x3301
  261. call __head_fr401_set_busctl
  262. LEDS 0x3303
  263. call __head_fr401_survey_sdram
  264. LEDS 0x3305
  265. call __head_fr451_set_protection
  266. bra __head_done_memmap
  267. __head_fr555_memmap:
  268. LEDS 0x3501
  269. call __head_fr555_set_busctl
  270. LEDS 0x3503
  271. call __head_fr555_survey_sdram
  272. LEDS 0x3505
  273. call __head_fr555_set_protection
  274. __head_done_memmap:
  275. #endif
  276. LEDS 0x0007
  277. ###############################################################################
  278. #
  279. # turn the data cache and MMU on
  280. # - for the FR451 this'll mean that the window through which the kernel is
  281. # viewed will change
  282. #
  283. ###############################################################################
  284. #ifdef CONFIG_MMU
  285. #define MMUMODE HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT
  286. #else
  287. #define MMUMODE HSR0_EIMMU|HSR0_EDMMU
  288. #endif
  289. movsg hsr0,gr5
  290. sethi.p %hi(MMUMODE),gr4
  291. setlo %lo(MMUMODE),gr4
  292. or gr4,gr5,gr5
  293. #if defined(CONFIG_FRV_DEFL_CACHE_WTHRU)
  294. sethi.p %hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
  295. setlo %lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
  296. #elif defined(CONFIG_FRV_DEFL_CACHE_WBACK)
  297. sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
  298. setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
  299. #elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND)
  300. sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
  301. setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
  302. movsg psr,gr6
  303. srli gr6,#24,gr6
  304. cmpi gr6,#0x50,icc0 // FR451
  305. beq icc0,#0,0f
  306. cmpi gr6,#0x40,icc0 // FR405
  307. bne icc0,#0,1f
  308. 0:
  309. # turn off write-allocate
  310. sethi.p %hi(HSR0_NWA),gr6
  311. setlo %lo(HSR0_NWA),gr6
  312. or gr4,gr6,gr4
  313. 1:
  314. #else
  315. #error No default cache configuration set
  316. #endif
  317. or gr4,gr5,gr5
  318. movgs gr5,hsr0
  319. bar
  320. LEDS 0x0008
  321. sethi.p %hi(__head_mmu_enabled),gr19
  322. setlo %lo(__head_mmu_enabled),gr19
  323. jmpl @(gr19,gr0)
  324. __head_mmu_enabled:
  325. icei @(gr0,gr0),#1
  326. dcei @(gr0,gr0),#1
  327. LEDS 0x0009
  328. #ifdef CONFIG_MMU
  329. call __head_fr451_finalise_protection
  330. #endif
  331. LEDS 0x000a
  332. ###############################################################################
  333. #
  334. # set up the runtime environment
  335. #
  336. ###############################################################################
  337. # clear the BSS area
  338. sethi.p %hi(__bss_start),gr4
  339. setlo %lo(__bss_start),gr4
  340. sethi.p %hi(_end),gr5
  341. setlo %lo(_end),gr5
  342. or.p gr0,gr0,gr18
  343. or gr0,gr0,gr19
  344. 0:
  345. stdi gr18,@(gr4,#0)
  346. stdi gr18,@(gr4,#8)
  347. stdi gr18,@(gr4,#16)
  348. stdi.p gr18,@(gr4,#24)
  349. addi gr4,#24,gr4
  350. subcc gr5,gr4,gr0,icc0
  351. bhi icc0,#2,0b
  352. LEDS 0x000b
  353. # save the SDRAM details
  354. sethi.p %hi(__sdram_old_base),gr4
  355. setlo %lo(__sdram_old_base),gr4
  356. st gr24,@(gr4,gr0)
  357. sethi.p %hi(__sdram_base),gr5
  358. setlo %lo(__sdram_base),gr5
  359. sethi.p %hi(memory_start),gr4
  360. setlo %lo(memory_start),gr4
  361. st gr5,@(gr4,gr0)
  362. add gr25,gr5,gr25
  363. sethi.p %hi(memory_end),gr4
  364. setlo %lo(memory_end),gr4
  365. st gr25,@(gr4,gr0)
  366. # point the TBR at the kernel trap table
  367. sethi.p %hi(__entry_kerneltrap_table),gr4
  368. setlo %lo(__entry_kerneltrap_table),gr4
  369. movgs gr4,tbr
  370. # set up the exception frame for init
  371. sethi.p %hi(__kernel_frame0_ptr),gr28
  372. setlo %lo(__kernel_frame0_ptr),gr28
  373. sethi.p %hi(_gp),gr16
  374. setlo %lo(_gp),gr16
  375. sethi.p %hi(__entry_usertrap_table),gr4
  376. setlo %lo(__entry_usertrap_table),gr4
  377. lddi @(gr28,#0),gr28 ; load __frame & current
  378. ldi.p @(gr29,#4),gr15 ; set current_thread
  379. or gr0,gr0,fp
  380. or gr28,gr0,sp
  381. sti.p gr4,@(gr28,REG_TBR)
  382. setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
  383. movgs gr5,isr
  384. # turn on and off various CPU services
  385. movsg psr,gr22
  386. sethi.p %hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
  387. setlo %lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
  388. or gr22,gr4,gr22
  389. movgs gr22,psr
  390. andi gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22
  391. ori gr22,#PSR_ET,gr22
  392. sti gr22,@(gr28,REG_PSR)
  393. ###############################################################################
  394. #
  395. # set up the registers and jump into the kernel
  396. #
  397. ###############################################################################
  398. LEDS 0x000c
  399. # initialise the processor and the peripherals
  400. #call SYMBOL_NAME(processor_init)
  401. #call SYMBOL_NAME(unit_init)
  402. #LEDS 0x0aff
  403. sethi.p #0xe5e5,gr3
  404. setlo #0xe5e5,gr3
  405. or.p gr3,gr0,gr4
  406. or gr3,gr0,gr5
  407. or.p gr3,gr0,gr6
  408. or gr3,gr0,gr7
  409. or.p gr3,gr0,gr8
  410. or gr3,gr0,gr9
  411. or.p gr3,gr0,gr10
  412. or gr3,gr0,gr11
  413. or.p gr3,gr0,gr12
  414. or gr3,gr0,gr13
  415. or.p gr3,gr0,gr14
  416. or gr3,gr0,gr17
  417. or.p gr3,gr0,gr18
  418. or gr3,gr0,gr19
  419. or.p gr3,gr0,gr20
  420. or gr3,gr0,gr21
  421. or.p gr3,gr0,gr23
  422. or gr3,gr0,gr24
  423. or.p gr3,gr0,gr25
  424. or gr3,gr0,gr26
  425. or.p gr3,gr0,gr27
  426. # or gr3,gr0,gr30
  427. or gr3,gr0,gr31
  428. movgs gr0,lr
  429. movgs gr0,lcr
  430. movgs gr0,ccr
  431. movgs gr0,cccr
  432. # initialise the virtual interrupt handling
  433. subcc gr0,gr0,gr0,icc2 /* set Z, clear C */
  434. #ifdef CONFIG_MMU
  435. movgs gr3,scr2
  436. movgs gr3,scr3
  437. #endif
  438. LEDS 0x0fff
  439. # invoke the debugging stub if present
  440. # - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c
  441. # (it will not return here)
  442. break
  443. .globl __debug_stub_init_break
  444. __debug_stub_init_break:
  445. # however, if you need to use an ICE, and don't care about using any userspace
  446. # debugging tools (such as the ptrace syscall), you can just step over the break
  447. # above and get to the kernel this way
  448. # look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed
  449. call start_kernel
  450. .globl __head_end
  451. __head_end:
  452. .size _boot, .-_boot
  453. # provide a point for GDB to place a break
  454. .section .text..start,"ax"
  455. .globl _start
  456. .balign 4
  457. _start:
  458. call _boot
  459. .previous
  460. ###############################################################################
  461. #
  462. # split a tile off of the region defined by GR8-GR9
  463. #
  464. # ENTRY: EXIT:
  465. # GR4 - IAMPR value representing tile
  466. # GR5 - DAMPR value representing tile
  467. # GR6 - IAMLR value representing tile
  468. # GR7 - DAMLR value representing tile
  469. # GR8 region base pointer [saved]
  470. # GR9 region top pointer updated to exclude new tile
  471. # GR11 xAMLR mask [saved]
  472. # GR25 SDRAM size [saved]
  473. # GR30 LED address [saved]
  474. #
  475. # - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling
  476. #
  477. ###############################################################################
  478. .globl __head_split_region
  479. .type __head_split_region,@function
  480. __head_split_region:
  481. subcc.p gr9,gr8,gr4,icc0
  482. setlos #31,gr5
  483. scan.p gr4,gr0,gr6
  484. beq icc0,#0,__head_region_empty
  485. sub.p gr5,gr6,gr6 ; bit number of highest set bit (1MB=>20)
  486. setlos #1,gr4
  487. sll.p gr4,gr6,gr4 ; size of region (1 << bitno)
  488. subi gr6,#17,gr6 ; 1MB => 0x03
  489. slli.p gr6,#4,gr6 ; 1MB => 0x30
  490. sub gr9,gr4,gr9 ; move uncovered top down
  491. or gr9,gr6,gr4
  492. ori gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4
  493. or.p gr4,gr0,gr5
  494. and gr4,gr11,gr6
  495. and.p gr5,gr11,gr7
  496. bralr
  497. __head_region_empty:
  498. or.p gr0,gr0,gr4
  499. or gr0,gr0,gr5
  500. or.p gr0,gr0,gr6
  501. or gr0,gr0,gr7
  502. bralr
  503. .size __head_split_region, .-__head_split_region
  504. ###############################################################################
  505. #
  506. # write the 32-bit hex number in GR8 to ttyS0
  507. #
  508. ###############################################################################
  509. #if 0
  510. .globl __head_write_to_ttyS0
  511. .type __head_write_to_ttyS0,@function
  512. __head_write_to_ttyS0:
  513. sethi.p %hi(0xfeff9c00),gr31
  514. setlo %lo(0xfeff9c00),gr31
  515. setlos #8,gr20
  516. 0: ldubi @(gr31,#5*8),gr21
  517. andi gr21,#0x60,gr21
  518. subicc gr21,#0x60,gr21,icc0
  519. bne icc0,#0,0b
  520. 1: srli gr8,#28,gr21
  521. slli gr8,#4,gr8
  522. addi gr21,#'0',gr21
  523. subicc gr21,#'9',gr0,icc0
  524. bls icc0,#2,2f
  525. addi gr21,#'A'-'0'-10,gr21
  526. 2:
  527. stbi gr21,@(gr31,#0*8)
  528. subicc gr20,#1,gr20,icc0
  529. bhi icc0,#2,1b
  530. setlos #'\r',gr21
  531. stbi gr21,@(gr31,#0*8)
  532. setlos #'\n',gr21
  533. stbi gr21,@(gr31,#0*8)
  534. 3: ldubi @(gr31,#5*8),gr21
  535. andi gr21,#0x60,gr21
  536. subicc gr21,#0x60,gr21,icc0
  537. bne icc0,#0,3b
  538. bralr
  539. .size __head_write_to_ttyS0, .-__head_write_to_ttyS0
  540. #endif