Converting asm function to C - Problems

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok so I have some example code of how to convert an long long int into a string of ascii characters. I have simulated it in studio and made a flow chart on how it works. I then wrote a C function to try and get the same results.

My problem is mainly that in asm you can use overflows in the temp registers easily yet in C is it much harder. I built a union that if packed properly should allow access to the whole value plus access to each byte segment.

I believe this is how the asm works:
- Value is loaded into r22:r25
- left shift value and if r26 overflow is > base, subtract the base
- after 32 shifts if r26 > base then subtract 7 (no idea why...)
- subtract ascii 0 from r26
- push the result onto the stack for later
- repeat untill r22:r25 = 0

My union packs the bits so that r26 is the equivalent of accu.mByte[4]. The problem is on the first shift ( accu.total = accu.total << 1; ) the program quits (goes to end of main and halts)

I have no idea if I am doing this right as this is the first time I have tried to convert asm to C.

;---------------------------------------------------------------------------
; Extended direct numeral string output (32bit version)
;
;Prototype: void xitoa (long value,	// value to be output
;                       char radix,	// radix
;                       char width);	// minimum width
;Size: 59/59 words
;
.global xitoa
.func xitoa
xitoa:
				;r25:r22 = value, r20 = base, r18 = digits
	clr	r31		;r31 = stack level
	ldi	r30, ' '	;r30 = sign
	ldi	r19, ' '	;r19 = filler
	sbrs	r20, 7		;When base indicates signd format and the value
	rjmp	0f		;is minus, add a '-'.
	neg	r20		;
	sbrs	r25, 7		;
	rjmp	0f		;
	ldi	r30, '-'	;
	com	r22		;
	com	r23		;
	com	r24		;
	com	r25		;
	adc	r22, r1		;
	adc	r23, r1		;
	adc	r24, r1		;
	adc	r25, r1		;/
0:	sbrs	r18, 7		;When digits indicates zero filled,
	rjmp	1f		;filler is '0'.
	neg	r18		;
	ldi	r19, '0'	;/
				;----- string conversion loop
1:	ldi	r21, 32		;r26 = r25:r22 % r20
	clr	r26		;r25:r22 /= r20
2:	lsl	r22		;
	rol	r23		;
	rol	r24		;
	rol	r25		;
	rol	r26		;
	cp	r26, r20	;
	brcs	3f		;
	sub	r26, r20	;
	inc	r22		;
3:	dec	r21		;
	brne	2b		;/
	cpi	r26, 10		;r26 is a numeral digit '0'-'F'
	brcs	4f		;
	subi	r26, -7		;
4:	subi	r26, -'0'	;/
	push	r26		;Stack it
	inc	r31		;/
	cp	r22, r1		;Repeat until r25:r22 gets zero
	cpc	r23, r1		;
	cpc	r24, r1		;
	cpc	r25, r1		;
	brne	1b		;/

	cpi	r30, '-'	;Minus sign if needed
	brne	5f		;
	push	r30		;
	inc	r31		;/
5:	cp	r31, r18	;Filler
	brcc	6f		;
	push	r19		;
	inc	r31		;
	rjmp	5b		;/

6:	pop	r24		;Flush stacked digits and exit
	rcall	xputc		;
	dec	r31		;
	brne	6b		;/

	ret
.endfunc
void myitoa(long value, int base, int length)
{
	unsigned int byte_cnt, shift_cnt;
	char buffer[34]; //32bits + sign + terminator

	typedef union{
		long long total;
		struct{
			unsigned int mByte[5];
		};
	} itoa_conv;

	itoa_conv accu;
	accu.total = value;
	byte_cnt = 0;

	while(1)
	{
		for(shift_cnt = 32; shift_cnt > 0; --shift_cnt)
		{
			accu.total = accu.total << 1;
			if( accu.mByte[4] > base )
				accu.mByte[4] -= base;
		}

		if( accu.mByte[4] > base )
			accu.mByte[4] -= -7;

		accu.mByte[4] -= '0';
		buffer[byte_cnt] = accu.mByte[4];
		byte_cnt++;

		if( (accu.mByte[0] + accu.mByte[1] + accu.mByte[2] + accu.mByte[3]) == 0)
			break;
	}

	if( byte_cnt < length )
	{
		buffer[byte_cnt] = '0';
		byte_cnt++;
	}

	for(; byte_cnt <= 0; --byte_cnt)
		xputc( buffer[byte_cnt] );

	accu.total = 0;

}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Ok so I have some example code of how to convert an long long int into a string of ascii characters.
Your example is 32 bits - "only" long int.
Why don't you use ltoa? http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#g1d4c7b84110553544081a69a0fc49c52

/Martin.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am in fact trying to create my own itoa() (Why? Because I want to implement it in a particular way!)

Is my C version the same flow as the asm version? I still have not got it working...

In general even writing my own C function and ignoring the asm I am unsure how to convert a long into a string. But I have been stepping through asm all day and feel kind of dumb.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But why is itoa_conv.total long long (64 bits)?
And I cannot see, why this function should/could work.

static void reverse(char s[])
{
    uint8_t c, i, j;

    for (i = 0, j = strlen(s)-1; i '9') {
             *s += 'A'-'9';
        }
        s++;
    } while ((n /= b) > 0);
    s++ = '\0';
    reverse(s);
}

/Martin.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I required a 32bit value to hold the value and after 32 left shifts and the - base maths the conversion of the value to ascii was done on the bits 33-40.

32bit Value in r22, r23, r24, r25
ops done on results in r26.

I did not know how to append a byte onto a long so I just use a long long for testing.

I will try out your code tomorrow, im to tired to tonight. Thanks for the response though, I will let you know if it works for me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW, the code posted by me above is for unsigned and does not handle the sign. But it should not be to complicated, to handle the '-'.

/Martin.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I am in fact trying to create my own itoa() (Why? Because I want to implement it in a particular way!)

This thread may be of great interest:
https://www.avrfreaks.net/index.p...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.