### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook (preview only)

### Author Topic: How to read function parameter in assembler code for AVR/Arduino delay function  (Read 6159 times)

#### ccrause

• Full Member
• Posts: 222
##### How to read function parameter in assembler code for AVR/Arduino delay function
« on: February 27, 2016, 12:44:38 pm »
I've had a stab at alternative code for an AVR delay function, http://forum.lazarus.freepascal.org/index.php/topic,30960.msg201014.html#msg201014

At the moment I have a delay_ms function that produces a delay of 1 millisecond, which can be used in a busy loop as follows:

Code: Pascal  [Select]
2.
3. {\$IFNDEF F_CPU}
4.   {\$WARNING F_CPU not defined, setting default value of 16 MHz}
5.   {\$MACRO ON}
6.   {\$define F_CPU:=16000000}
7. {\$ENDIF}
8.
9. const
10.   PB5 = (1 shl 5);
11.
12. // Cycle count = 2 + 4*(x-1) + 3 + 4
13. // = 5 + 4*x
14. procedure delay_ms(); assembler;
15. const
16.   x = ((F_CPU div 1000) - 5) div 4;
17.   x_l = x and 255;
18.   x_h = x shr 8;
19.
20. label
21.   Loop;
22.
23. asm
24.   // XH: XL register is same as R26: R27 register combination
25.   LDI XH, x_h //Set high byte   1 cycle
26.   LDI XL, x_l //Set low byte    1 cycle
27.
28. Loop:
29.   SBIW XL,1 //subtract one from word 2 cycles
30.   BRNE Loop //Take branch = 2 cycles / No branch = 1 cycle (last iteration of loop)
31.   // ret is implicitly inserted here by compiler  4 cycles
32. end;
33.
34. var
35.   i: uint16;
36.
37. begin
38.   DDRB := DDRB or PB5; // Set pin 5 of port B to output
39.
40.   while true do
41.   begin
42.     i := 500;
43.     repeat
44.       delay_ms();
45.       dec(i);
46.     until i = 0;
47.
48.     PORTB := PORTB XOR PB5;  // toggle pin 5 of port B on/off
49.   end;
50. end.

The delay_ms function above gives a constant delay.  I would like to pass a parameter specifying the delay required to this function and then build a countdown loop in assembly.  My problem is that I don't know how to access a procedure/function parameter in assembler.  Can anyone help in fixing the following pseudocode so that it loads the variable t into two 8 bit registers please?
Code: Pascal  [Select]
1. procedure delay_ms(t: uint16); assembler;
2. label
3.   Loop;
4.
5. asm
6.   mov XH, hi8(t)
7.   mov XL, lo8(t)
8.
9. Loop:
10.   SBIW XL,1
11.   BRNE Loop
12. end;
13.

When I try to compile a program with this code I get the following error:
Code: Pascal  [Select]
1. Error: Cannot use local variable or parameters here

• Hero Member
• Posts: 9419
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #1 on: February 27, 2016, 01:07:16 pm »
This may be enough:
Code: Pascal  [Select]
1. procedure delay_ms(const t: uint16); assembler;
2. label
3.   Loop;
4.
5. asm
6.   mov XH, hi8(t)
7.   mov XL, lo8(t)
8.
9. Loop:
10.   SBIW XL,1
11.   BRNE Loop
12. end;
also related to equus asinus.

#### ccrause

• Full Member
• Posts: 222
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #2 on: February 28, 2016, 07:28:00 am »
This may be enough:
Code: Pascal  [Select]
1. procedure delay_ms(const t: uint16); assembler;
2. label
3.   Loop;
4.
5. asm
6.   mov XH, hi8(t)
7.   mov XL, lo8(t)
8.
9. Loop:
10.   SBIW XL,1
11.   BRNE Loop
12. end;

Thanks Thaddy.  I did try that but then I get a compiler error: Cannot use local variable or parameters here at the hi8(t) and lo8(t) instructions.

I guess I have to figure out in which registers the value is passed, then I can proceed from there?

• Hero Member
• Posts: 9419
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #3 on: February 28, 2016, 08:53:55 am »
Can't you use a byte record? instead of the UINT16? That should work and you can also cast it.
Note I assume little endian. If big endian change l and h. This way there aren't any locals for sure.
Code: Pascal  [Select]
1. Type
2.   TMyUINT16 = packed record
3.     l:byte;
4.     h:byte;
5.   end;
6.
7.    procedure delay_ms(const t: TMyUint16); assembler;
8.    label
9.      Loop;
10.      asm
11.        mov XH, t.h
12.        mov XL, t.l
13.
14.     Loop:
15.       SBIW XL,1
16.       BRNE Loop
17.     end;
18.

Allternatively, but should also work:
Code: Pascal  [Select]
1.   procedure delay_ms(const t: Uint16); assembler;
2.    label
3.      Loop;
4.      asm
5.        mov XH, TMyUint16(t).h
6.        mov XL, TMyUint16(t).l
7.   ...
8.
« Last Edit: February 28, 2016, 09:07:25 am by Thaddy »
also related to equus asinus.

#### ccrause

• Full Member
• Posts: 222
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #4 on: February 28, 2016, 03:47:23 pm »
Thanks Thaddy, your example compiles fine, but the GNU assembler chokes on the generated assembler code. Compiling the following snippet:
Code: Pascal  [Select]
1. Type
2.   TMyUINT16 = packed record
3.     l:byte;
4.     h:byte;
5.   end;
6.
7. procedure delay_ms2(const t: uint16); assembler;
8. label
9.   Loop;
10. asm
11.   mov XH, TMyUint16(t).h
12.   mov XL, TMyUint16(t).l
13. Loop:
14.   SBIW XL,1
15.   BRNE Loop
16. end;

generates the following assembler snippet:
Code: ASM  [Select]
2.         mov     r27,r24+1
3.         mov     r26,r24
4. .Lj8:
5.         sbiw    r26,1
6.         brne    .Lj8
7.         ret
8. .Le1:
10.

The AVR assembler generates the following error:
blink_test.s:19: Error: garbage at end of line

It seems as if the fpc compiler translated the line mov XH, TMyUint16(t).h  into mov r27,r24+1.  From the rest of the generated assembler code it seems as if the value passed to the procedure is loaded into r24:r25, so I suspected that the compiler was trying to generate "the next register following r24" and ended up writing r24+1 instead of r25.

If so I guess this is a bug?

• Hero Member
• Posts: 9419
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #5 on: February 28, 2016, 09:07:39 pm »
Well, we tried, Doesn't mean it is a bug but maybe you should file one.
I am out of ideas. The code looks good by now.
also related to equus asinus.

#### ccrause

• Full Member
• Posts: 222
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #6 on: February 29, 2016, 08:44:55 am »

#### avra

• Hero Member
• Posts: 1757
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #7 on: February 29, 2016, 02:02:17 pm »
A little off topic, but once the bug is solved you can take a look at several ways to generate cycle exact delays on AVR:
http://forum.e-lab.de/topic.php?t=1822&page=1#post8
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

#### Laksen

• Hero Member
• Posts: 637
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #8 on: February 29, 2016, 02:24:56 pm »
There's no way to do that currently.

You just have to know the calling convention.

#### ccrause

• Full Member
• Posts: 222
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #9 on: March 01, 2016, 07:20:20 am »
A little off topic, but once the bug is solved you can take a look at several ways to generate cycle exact delays on AVR:
http://forum.e-lab.de/topic.php?t=1822&page=1#post8

Looks useful, thanks avra

#### ccrause

• Full Member
• Posts: 222
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #10 on: March 01, 2016, 07:48:12 am »
There's no way to do that currently.

You just have to know the calling convention.

Right, so according to the wiki I should follow the avr-libc convention, so I should assume the following:
Code: Pascal  [Select]
1. procedure delay_ms2(const t: uint16); assembler;
2. asm
3.   // First 16 bit parameter passed as lo(t) -> R24 and hi(t) -> R25
4.   mov XH, R25
5.   mov XL, R24
6. ...

Is this right?

I would still prefer it if the compiler could substitute the appropriate registers from the parameter name reference though, I'm sure I will confuse myself at some point with the order of registers, little/big endianness etc...

#### ccrause

• Full Member
• Posts: 222
##### Re: How to read function parameter in assembler code for AVR/Arduino delay function
« Reply #11 on: January 01, 2018, 09:44:09 am »
There's no way to do that currently.

You just have to know the calling convention.
Thanks to Jeppe for fixing the compiler to accept the type cast suggested by Thaddy.  The following code now works correctly:

Allternatively, but should also work:
Code: Pascal  [Select]
1.   procedure delay_ms(const t: Uint16); assembler;
2.    label
3.      Loop;
4.      asm
5.        mov XH, TMyUint16(t).h
6.        mov XL, TMyUint16(t).l
7.   ...
8.