View previous topic :: View next topic |
Author |
Message |
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
Writing equivalent of MPASM $+1 in inline assembly |
Posted: Sun Jul 11, 2010 1:32 pm |
|
|
I want to writing "something" that will be equivalent to:
Code: |
#asm
goto $+1
goto $+1
#endasm
|
this should be 2 words.
This is to generate a delay of 4 ticks.
Conceptually, I could write the one below, but waste 2 words
Code: |
#asm
NOP
NOP
NOP
NOP
#endasm
|
.. or 1
Code: |
#asm
goto next1
next1:
nop
nop
#endasm
|
Any hints on getting the first construct working or any 2 word suggestion without extra variables? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 11, 2010 2:01 pm |
|
|
Use a macro. Example:
Code: |
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#define delay4 \
NOP \
NOP \
NOP \
NOP
//==========================================
void main()
{
#asm
movlw 0x55
delay4
movlw 0xAA
#endasm
while(1);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19536
|
|
Posted: Sun Jul 11, 2010 2:38 pm |
|
|
Surely the simplest way, is to let the compiler do it for you?.
delay_cycles(4);
This generates two jumps, to give 4 cycles, and two words used, exactly as required.
Code: |
.................... delay_cycles(4);
00E3: GOTO 0E4
00E4: GOTO 0E5
|
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 11, 2010 2:42 pm |
|
|
I assumed he wanted to embed a delay in an #asm block. I could be wrong. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19536
|
|
Posted: Sun Jul 11, 2010 3:01 pm |
|
|
True.
Except of course, that even 'in an assembler block', there is no reason really, not to just have an endasm, the delay, and another asm. Could even be done as a macro.
That the delay gives exactly the code he wants, would seem to make this the ideal choice.
Best Wishes |
|
|
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
|
Posted: Sun Jul 11, 2010 5:59 pm |
|
|
WHOA! We had a delay_cycles function?
:-O
Damn... should have read the manual more carefully.
By the way - do you guys know that delays more than 153uS are inaccurate in CCS C?
Delays till 153uS are accurate, but after that 0.3% error creeps in.
I am not sure *why* CCS has used the kind of code they use in the delay subroutine that get generated above 153uS - there were *much* faster and 100% accurate ways!
Has some one analyzed the delay code in CCS C?
Otherwise, maybe I will share my findings and we can take that forward ( will there be people interested in such a kind of thing? ) |
|
|
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
|
Posted: Sun Jul 11, 2010 6:04 pm |
|
|
PCM programmer wrote: | I assumed he wanted to embed a delay in an #asm block. I could be wrong. |
Your assumption is correct - however, I wanted a *smaller* version of 4 NOPs that would take just as much time.
Do you know how? ( delay_cycles is cool for now ) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19536
|
|
Posted: Mon Jul 12, 2010 4:28 am |
|
|
The nearest I can think of, would be (as a standalone function):
Code: |
#inline
void delay4(void) {
#asm
GOTO inner1
inner1:
GOTO inner2
inner2:
#endasm
}
|
Or just the lines between #asm, and #endasm, if in an existing assembler block.
Best Wishes |
|
|
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
|
Posted: Mon Jul 12, 2010 11:48 am |
|
|
Ah - so no goto $+1 shortcut in the embedded asm in PIC C.
Not a problem though - we can always use labels :-) |
|
|
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
|
Posted: Tue Jul 13, 2010 5:30 am |
|
|
Ttelmah wrote: | The nearest I can think of, would be (as a standalone function):
Code: |
#inline
void delay4(void) {
#asm
GOTO inner1
inner1:
GOTO inner2
inner2:
#endasm
}
|
Or just the lines between #asm, and #endasm, if in an existing assembler block.
Best Wishes |
I don't know what I am doing wrong, but when I use the suggested code in isolation, it gets assembled correctly :
Code: | #inline
void delay4(void) {
#asm
GOTO inner1
inner1:
GOTO inner2
inner2:
#endasm
}
|
is correctly assembled as 2 gotos:
Code: | .................... void delay4(void) {
.................... #asm
.................... GOTO inner1
*
0172: GOTO 173
.................... inner1:
.................... GOTO inner2
0173: GOTO 174
.................... inner2:
.................... #endasm
.................... }
|
However, when I put this in a larger function, the assembled code not only has 1 goto instead of the expected 2, but the code goes into an infinite loop/hangs!
Here is the piece of code I am talking about:
Code: | #inline
void delay_ticks()
{
unsigned int8 CounterA = 74;
unsigned int8 CounterB = 2;
#asm
loop:
decfsz CounterA,1
goto loop
decfsz CounterB,1
goto loop
GOTO inner1
inner1:
GOTO inner2
inner2:
#endasm
//delay_cycles( 4 );
}
|
.. and here is how it gets assembled:
Code: | .................... #inline
.................... void delay_ticks()
.................... {
*
0174: MOVLW 4A
0175: MOVWF 21
0176: MOVLW 02
0177: MOVWF 22
....................
.................... unsigned int8 CounterA = 74;
.................... unsigned int8 CounterB = 2;
....................
.................... #asm
.................... loop:
.................... decfsz CounterA,1
0178: DECFSZ 21,F
.................... goto loop
0179: GOTO 178
.................... decfsz CounterB,1
017A: DECFSZ 22,F
.................... goto loop
017B: GOTO 178
....................
.................... GOTO inner1
.................... inner1:
.................... GOTO inner2
017C: GOTO 17D
.................... inner2:
.................... #endasm
....................
.................... //delay_cycles( 4 );
.................... }
*
017D: CLRF 10
....
|
What gives?
1. Why is the second goto missing in the later function?
2. Why does the loop hang - although, from reading the code, things do not look out of the ordinary? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19536
|
|
Posted: Tue Jul 13, 2010 6:56 am |
|
|
You need:
Code: |
#inline
void delay_ticks() {
unsigned int8 CounterA = 74;
unsigned int8 CounterB = 2;
#asm
loop:
decfsz CounterA,1
goto loop
decfsz CounterB,1
goto loop
#endasm
#asm ASIS
GOTO inner1
inner1:
GOTO inner2
inner2:
#endasm
}
|
The problem is that the optimiser sees the second jump and says 'this is a waste of time'....
Best Wishes |
|
|
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
|
Posted: Tue Jul 13, 2010 7:14 am |
|
|
Ttelmah wrote: |
The problem is that the optimiser sees the second jump and says 'this is a waste of time'.... |
In that case why does this work correctly:
Code: | #inline
void delay4(void) {
#asm
GOTO inner1
inner1:
GOTO inner2
inner2:
#endasm
}
|
is correctly assembled as 2 gotos:
Code: | .................... void delay4(void) {
.................... #asm
.................... GOTO inner1
*
0172: GOTO 173
.................... inner1:
.................... GOTO inner2
0173: GOTO 174
.................... inner2:
.................... #endasm
.................... } |
|
|
|
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
|
Posted: Thu Jul 15, 2010 6:23 pm |
|
|
Well?
:-) |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jul 15, 2010 8:29 pm |
|
|
Without detailed knowledge of the compiler's internals we can only guess why the optimization is not performed in all situations, but it is not a bug. Not the most optimal code either, but creating the perfect optimizer is extremely difficult and this is where the difference between good and better compilers becomes visible.
If you use the ASIS directive, the code should always be generated as you have coded. If not, that's a bug and you should report it to CCS. |
|
|
equack
Joined: 21 Sep 2009 Posts: 21
|
|
Posted: Mon Sep 27, 2010 7:28 pm |
|
|
WHAT? The compiler optimizes my inline assembly code by default?
That's terrible. Inline assembly is for getting the PIC to do _exactly_ what you want. <sigh> |
|
|
|