Question about Propeller assembly multiply and divide operations
grahamj1978
Posts: 3
in Propeller 1
I've been trying to learn a bit about propeller assembly. I hope to be able to eventually write code in assembly, which I can offload to a cog to run when called. To start I coded a toy function in C, which worked as expected. However, I wanted to see what the associated assembly looked like, so I took a look and got some unexpected results (see below).
Here's the function in C:
void AssAlg1(int *in1)
{
unsigned short temp=(*in1);
unsigned short temp2=5;
unsigned short temp3;
temp++;
temp++;
temp=temp+temp2;
temp=temp*3;
temp=temp-13;
temp=temp/temp2;
(*in1)=(temp);
return;
}
And here's the resulting assembly output (generated from propeller-elf-objdump):
000007f8 <_AssAlg1>:
7f8: f2 00 0e 04 rdword 1c <r7>, 0 <__clkfreq>
7fc: 27 70 add r7, #0x7
7fe: 0a 60 mov r6,r0
800: 0a 07 mov r0,r7
802: a1 03 mov r1,#0x3
804: f2 2e 01 60 and 0 <__clkfreq>, 4b8 <__MASK_0000FFFF>
808: 07 mul
809: e7 70 d1 xmov r7, r0 sub r7, #0xd
80c: 0a 07 mov r0,r7
80e: f2 2e 01 60 and 0 <__clkfreq>, 4b8 <__MASK_0000FFFF>
812: a1 05 mov r1,#0x5
814: 08 udiv
815: f2 2e 01 60 and 0 <__clkfreq>, 4b8 <__MASK_0000FFFF>
819: 10 6f wrlong r0, r6
81b: 02 lret
What's bothering me is how it handles the multiply and divide operations. I took a look as the assembly reference and can't find a mul or udiv instruction. Exactly what's going on here? I assume this is some kind of macro, but I haven't been able to locate any reference to either.
Any ideas?
For completeness here's the full assembly code listing from .asm file:
Here's the function in C:
void AssAlg1(int *in1)
{
unsigned short temp=(*in1);
unsigned short temp2=5;
unsigned short temp3;
temp++;
temp++;
temp=temp+temp2;
temp=temp*3;
temp=temp-13;
temp=temp/temp2;
(*in1)=(temp);
return;
}
And here's the resulting assembly output (generated from propeller-elf-objdump):
000007f8 <_AssAlg1>:
7f8: f2 00 0e 04 rdword 1c <r7>, 0 <__clkfreq>
7fc: 27 70 add r7, #0x7
7fe: 0a 60 mov r6,r0
800: 0a 07 mov r0,r7
802: a1 03 mov r1,#0x3
804: f2 2e 01 60 and 0 <__clkfreq>, 4b8 <__MASK_0000FFFF>
808: 07 mul
809: e7 70 d1 xmov r7, r0 sub r7, #0xd
80c: 0a 07 mov r0,r7
80e: f2 2e 01 60 and 0 <__clkfreq>, 4b8 <__MASK_0000FFFF>
812: a1 05 mov r1,#0x5
814: 08 udiv
815: f2 2e 01 60 and 0 <__clkfreq>, 4b8 <__MASK_0000FFFF>
819: 10 6f wrlong r0, r6
81b: 02 lret
What's bothering me is how it handles the multiply and divide operations. I took a look as the assembly reference and can't find a mul or udiv instruction. Exactly what's going on here? I assume this is some kind of macro, but I haven't been able to locate any reference to either.
Any ideas?
For completeness here's the full assembly code listing from .asm file:
5:assembCode.c **** void AssAlg1(int *in1)
6:assembCode.c **** {
7 .loc 1 6 0
8 .LVL0
7:assembCode.c **** unsigned short temp=(*in1);
9 .loc 1 7 0
10 0000 F2000E04 rdword r7, r0
11 .LVL1
8:assembCode.c **** unsigned short temp2=5;
9:assembCode.c **** unsigned short temp3;
10:assembCode.c ****
11:assembCode.c **** temp++;
12:assembCode.c **** temp++;
13:assembCode.c **** temp=temp+temp2;
12 .loc 1 13 0
13 0004 2770 add r7, #7
14 .LVL2
6:assembCode.c **** {
15 .loc 1 6 0
16 0006 0A60 mov r6, r0
17 .loc 1 13 0
18 0008 0A07 mov r0, r7
19 .LVL3
14:assembCode.c ****
15:assembCode.c **** temp=temp*3;
20 .loc 1 15 0
21 000a A103 mov r1, #3
13:assembCode.c **** temp=temp+temp2;
22 .loc 1 13 0
23 000c F2000060 and r0,__MASK_0000FFFF
24 .LVL4
25 .loc 1 15 0
26 0010 07 lmul
27 .LVL5
28 .LVL6
29 0011 E770D1 xmov r7,r0 sub r7,#13
16:assembCode.c **** temp=temp-13;
30 .loc 1 16 0
31 0014 0A07 mov r0, r7
32 .LVL7
33 0016 F2000060 and r0,__MASK_0000FFFF
34 .LVL8
17:assembCode.c **** temp=temp/temp2;
35 .loc 1 17 0
36 001a A105 mov r1, #5
37 001c 08 ludiv
38 .LVL9
18:assembCode.c **** (*in1)=(temp);
39 .loc 1 18 0
40 001d F2000060 and r0,__MASK_0000FFFF
41 0021 106F wrlong r0, r6
19:assembCode.c **** return;
20:assembCode.c **** }
42 .loc 1 20 0
43 0023 02 lret
6:assembCode.c **** {
7 .loc 1 6 0
8 .LVL0
7:assembCode.c **** unsigned short temp=(*in1);
9 .loc 1 7 0
10 0000 F2000E04 rdword r7, r0
11 .LVL1
8:assembCode.c **** unsigned short temp2=5;
9:assembCode.c **** unsigned short temp3;
10:assembCode.c ****
11:assembCode.c **** temp++;
12:assembCode.c **** temp++;
13:assembCode.c **** temp=temp+temp2;
12 .loc 1 13 0
13 0004 2770 add r7, #7
14 .LVL2
6:assembCode.c **** {
15 .loc 1 6 0
16 0006 0A60 mov r6, r0
17 .loc 1 13 0
18 0008 0A07 mov r0, r7
19 .LVL3
14:assembCode.c ****
15:assembCode.c **** temp=temp*3;
20 .loc 1 15 0
21 000a A103 mov r1, #3
13:assembCode.c **** temp=temp+temp2;
22 .loc 1 13 0
23 000c F2000060 and r0,__MASK_0000FFFF
24 .LVL4
25 .loc 1 15 0
26 0010 07 lmul
27 .LVL5
28 .LVL6
29 0011 E770D1 xmov r7,r0 sub r7,#13
16:assembCode.c **** temp=temp-13;
30 .loc 1 16 0
31 0014 0A07 mov r0, r7
32 .LVL7
33 0016 F2000060 and r0,__MASK_0000FFFF
34 .LVL8
17:assembCode.c **** temp=temp/temp2;
35 .loc 1 17 0
36 001a A105 mov r1, #5
37 001c 08 ludiv
38 .LVL9
18:assembCode.c **** (*in1)=(temp);
39 .loc 1 18 0
40 001d F2000060 and r0,__MASK_0000FFFF
41 0021 106F wrlong r0, r6
19:assembCode.c **** return;
20:assembCode.c **** }
42 .loc 1 20 0
43 0023 02 lret
Comments
A good compiler will use its internal 16*16 call function for run time math,
but if the compiler sees that it can simple use left or right shift and maybe finish with a addition/subtraction, it will create custom inline routine just for that.
So if you want to do mul and div you need to write the PASM to do that, using shift, add, subtract or whatever.
After all, I'm sure you learned in primary school that multiply is just repeated additions. You can use the primary school methods of mul and div.
You can do that by hand in PASM. Or you can use what the compilers generate for you. Spin, C and so on.
Sorry I can't provide links off hand but if you search around you will find mul and div code in PASM if you want to write it by hand.
I'm still not sure how exactly the routines are being called in my code. If you look in the attached output.txt dumpfile that I generated you should be able to find the aforementioned mul and udiv macros. But I still question how exactly they are being called by the assembly code without using an explicit 'call' command.
Also, @DavidZemon, thanks for the tip. That should save me some trouble.
If you're trying to learn Propeller Assembly (PASM) you'll have much better luck looking at code compiled in LMM mode or even better COG mode. In COG mode the compiler produces pure PASM, which must run in the COGs internal memory. In LMM mode it produces PASM that is "interpreted" by a very simple interpreter which loads instructions from HUB and executes them one at a time. The difference mainy shows up in jumps -- in COG mode real jump instructions are produced, in LMM special sequences of instructions are produced to modify the register the interpreter is using to fetch from HUB.