0,0 → 1,216 |
/* Copyright (c) 2005,2007 Dmitry Xmelkov |
All rights reserved. |
|
Redistribution and use in source and binary forms, with or without |
modification, are permitted provided that the following conditions are met: |
|
* Redistributions of source code must retain the above copyright |
notice, this list of conditions and the following disclaimer. |
* Redistributions in binary form must reproduce the above copyright |
notice, this list of conditions and the following disclaimer in |
the documentation and/or other materials provided with the |
distribution. |
* Neither the name of the copyright holders nor the names of |
contributors may be used to endorse or promote products derived |
from this software without specific prior written permission. |
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. */ |
|
/* $Id: ultoa_invert.S 1944 2009-04-01 23:12:20Z arcanum $ */ |
|
#ifndef __DOXYGEN__ |
|
#include "macros.inc" |
#include "ntz.h" |
#include "xtoa_fast.h" |
|
/* -------------------------------------------------------------------- |
char * __ultoa_invert (unsigned long val, char * str, int base) |
|
This function is intended for usage as internal printf's one. |
It differs from others of `xtoa_fast' family: |
* srt[] will NOT 0 terminated. |
* Sequence of digits is inverted. |
* It returns pointer to first byte after a string. |
* Only `XTOA_UPPER' flag is operated. |
Notes: |
* base: check only 8 and 16, all others are treated as 10. |
(internal printf's function). |
*/ |
|
/* Input */ |
#define v_lo r22 |
#define v_hi r23 |
#define v_hlo r24 |
#define v_hhi r25 |
#define str_lo r20 |
#define str_hi r21 |
#define base r18 |
#define flags r19 |
|
/* Used */ |
#define v_fifth r26 /* val: bits 39..32 */ |
#define t_lo r18 /* temporary for shifted `val' */ |
#define t_hi r19 |
#define t_hlo r20 |
#define t_hhi r21 |
#define symb r20 /* write to string */ |
#define cnt r27 /* shift loop counter, local arg */ |
|
/* Fixed */ |
#define rzero r1 |
|
/* ASSEMBLY_CLIB_SECTION */ |
.global __ultoa_invert |
.type __ultoa_invert, "function" |
|
__ultoa_invert: |
X_movw ZL, str_lo |
clr v_fifth ; needed for all (ultoa_lsr) |
cpi base, 8 |
breq .L_oct |
cpi base, 16 |
breq .L_hex |
|
; decimal format |
clt ; flag of val == 0 |
.L_dec_loop: |
push v_lo ; to calculate remander |
; val &= ~1 |
andi v_lo, ~1 |
; val += 2 |
subi v_lo, lo8(-2) |
sbci v_hi, hi8(-2) |
sbci v_hlo, hlo8(-2) |
sbci v_hhi, hhi8(-2) |
sbci v_fifth, hhi8(-2) |
; val += val/2 |
ldi cnt, 1 |
rcall .L_div_add |
; val += val/16 |
ldi cnt, 4 |
rcall .L_div_add |
; val += val/256 |
add v_lo, v_hi |
adc v_hi, v_hlo |
adc v_hlo, v_hhi |
adc v_hhi, v_fifth |
adc v_fifth, rzero |
; val += val/65536 |
add v_lo, v_hlo |
adc v_hi, v_hhi |
adc v_hlo, v_fifth |
adc v_hhi, rzero |
adc v_fifth, rzero |
; val += val >> 32 |
add v_lo, v_fifth |
adc v_hi, rzero |
adc v_hlo, rzero |
adc v_hhi, rzero |
adc v_fifth, rzero |
; division result: val /= 16 |
rcall .L_lsr_4 ; v_fitth := 0 |
brne 1f |
set ; T := Z flag |
1: |
; rem: val_original - 10*val |
pop t_hi |
#if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__ |
ldi t_lo, 10 |
mul t_lo, v_lo |
clr r1 |
#else |
mov r0, v_lo |
lsl r0 |
sub t_hi, r0 |
lsl r0 |
lsl r0 |
#endif |
sub t_hi, r0 |
; output digit |
subi t_hi, lo8(-'0') |
st Z+, t_hi |
; quotient == 0 ? |
brtc .L_dec_loop |
; end of string |
.L_eos: |
X_movw r24, ZL |
ret |
|
; octal format |
.L_oct: |
mov symb, v_lo |
andi symb, 7 |
subi symb, lo8(-'0') |
st Z+, symb |
ldi cnt, 3 |
rcall .L_lsr |
brne .L_oct |
rjmp .L_eos |
|
; hex format |
.L_hex: |
mov symb, v_lo |
andi symb, 0x0f |
subi symb, lo8(-'0') |
cpi symb, '9' + 1 |
brlo 3f |
subi symb, lo8('9' + 1 - 'a') |
sbrc flags, ntz(XTOA_UPPER) - 8 |
subi symb, lo8('a' - 'A') |
3: st Z+, symb |
rcall .L_lsr_4 |
brne .L_hex |
rjmp .L_eos |
|
.L_lsr_4: |
ldi cnt, 4 |
.L_lsr: |
lsr v_fifth |
ror v_hhi |
ror v_hlo |
ror v_hi |
ror v_lo |
dec cnt |
brne .L_lsr |
; tst |
sbiw v_hlo, 0 ; only Z flag is needed |
cpc v_lo, rzero |
cpc v_hi, rzero |
ret |
|
.L_div_add: |
; copy to temporary |
X_movw t_lo, v_lo |
X_movw t_hlo, v_hlo |
mov r0, v_fifth |
; lsr temporary |
7: lsr r0 |
ror t_hhi |
ror t_hlo |
ror t_hi |
ror t_lo |
dec cnt |
brne 7b |
; add |
add v_lo, t_lo |
adc v_hi, t_hi |
adc v_hlo, t_hlo |
adc v_hhi, t_hhi |
adc v_fifth, r0 ; here r0 == 0 |
ret |
|
.size __ultoa_invert, . - __ultoa_invert |
.end |
|
#endif /* !__DOXYGEN__ */ |