C to Assembly II

Thread Starter

MaxHeadRoom

Joined Jul 18, 2013
30,654
Converting a program and I couldn't find exact confirmation but I assume the C instr.
while(1)
would equate to:
Loop:
goto loop ; Waiting for interrupt. ?
Max.
 

hexreader

Joined Apr 16, 2011
619
Sounds reasonable :)

Assuming that you correctly set up an interrupt before the infinite loop.....

Why are you keeping exact MCU and compiler name/version secret?

Your question might seem reasonable to you, but for respondents, background information motivates a better response.
 

Thread Starter

MaxHeadRoom

Joined Jul 18, 2013
30,654
I will have to ask again. Why do you have to convert it to assembler?
Maybe I misunderstood your question the first time!;)
I am more comfortable and presently more adept working in Assembler.
After conversion I want to adapt to different family (18F) and expand it.
Max.
 

AlbertHall

Joined Jun 4, 2014
12,625
C is much more portable than assembler even embedded in a PIC. There wouldn't be much to change to put the C in an 18F. You could also make it a learning experience. Just saying...
 

qrb14143

Joined Mar 6, 2017
112
Some assemblers even have a handy shortcut for this:
JMP $
on the MSP430 just jumps to the location of itself which saves you a line of code.
It may also be better to go into a low power mode once you have done your configuration and then let the interrupt wake up the device. Saves burning CPU cycles and hence power whizzing round in circles.

Converting a program and I couldn't find exact confirmation but I assume the C instr.
while(1)
would equate to:
Loop:
goto loop ; Waiting for interrupt. ?
Max.
 

Thread Starter

MaxHeadRoom

Joined Jul 18, 2013
30,654
Some assemblers even have a handy shortcut for this:
JMP $
on the MSP430 just jumps to the location of itself which saves you a line of code.
It may also be better to go into a low power mode once you have done your configuration and then let the interrupt wake up the device. Saves burning CPU cycles and hence power whizzing round in circles.
In this case the interrupt is constant after every TMR0 roll over so there is no lengthy 'rest' period!
No confirmations yet on the equivalent?:(
Max.
 

Papabravo

Joined Feb 24, 2006
22,082
Depending on the interplay between instruction scheduling and interrupt responses you may or may not be able to use a given equivalent instruction sequence without problems. At todays clock speeds there is no real reason to make such a loop as tight as a single instruction. In modern architectures you should be able to afford a "do nothing loop" that is at least, longer than the pipeline.

My favorite "do nothing loop" computes non- volatile checksums. Never had a problem with that one.
 

philba

Joined Aug 17, 2017
959
To the original question, yes, while(1) { <some code>} is a "forever" loop. A more complete syntax is while(<expression>) { <some code>} where <expression> is evaluated and if non-zero, <some code> is executed. Since 1 always evaluates to non-zero, <some code> is always executed.

On the portability of C/C++, there is a huge body of work about writing portable code. And portability can mean many things. While it is never 100%, C/C++ is far ahead of what ever is in 2nd place. You have to go about making sure you write portable code and if you follow a clear set of guidelines you will have an easy time moving your code. For micros, this often means using #defines and isolating non-portable stuff to a HAL like layer. If you look at Arduino, they actually do a very good job of this. Arduino code can be run on a very broad range of processors AVR, x86, lots of ARM variants.
 

Motanache

Joined Mar 2, 2015
652
Converting a program and I couldn't find exact confirmation but I assume the C instr.
while(1)
would equate to:
Loop:
goto loop ; Waiting for interrupt. ?
Max.
It's up to the compiler to interpret it.
MikroC offers a listing file in assembler. It is not complete but is useful.

For me there is a difference between:
while(1)
and
while(1==1)
and
x=1;
while(x)

The compiler might "observe" that the condition is constant and provide an infinite cycle.
 

Thread Starter

MaxHeadRoom

Joined Jul 18, 2013
30,654
I wouldn't have thought it would invoke any ambiguity?
I would assume that in writing the said referenced C program, the authors intention I thought would have been evident?
I have the MikroC manual and it does not exactly show a clear definition.
Max.
 

WBahn

Joined Mar 31, 2012
32,823
Converting a program and I couldn't find exact confirmation but I assume the C instr.
while(1)
would equate to:
Loop:
goto loop ; Waiting for interrupt. ?
Max.
You are missing a semicolon. As written, whatever the next statement after the while(1) is included in the loop.

That aside, the semantics of your translated code match, but the implementation may or may not. That will depend on the capabilities of the compiler.

A pure, raw translation would first evaluate the test expression in the while statement (and get a value of 1 in this case). It would then do something that effectively compares this value to 0 (there are a number of ways to do this). If they compare as equal, an unconditional jump to the first statement after the while() statement will be executed. Otherwise execution will continue and, after all the statements in the while() block are executed, an unconditional jump to the first instruction involved in evaluating the test expression will be executed.

A real simplistic compiler will follow this code generation pattern even for a loop as simple as yours. For years the optimizing ability of compilers for embedded processors tended to be on this end of the spectrum compared to mainline compilers as a simple matter of economies of scale -- any given embedded architecture did not have enough demand for an optimizing C compiler to warrant the time required to improve its performance. But that has changed radically and now many good optimizing compilers are available for embedded architectures.
 

WBahn

Joined Mar 31, 2012
32,823
I wouldn't have thought it would invoke any ambiguity?
I would assume that in writing the said referenced C program, the authors intention I thought would have been evident?
I have the MikroC manual and it does not exactly show a clear definition.
Max.
Semantically they are the same. Implementation wise they may or may not be.

There's a reason why there are three different ways to increment the value stored in an integer variable by 1.

c = c + 1;
c += 1;
c++;

Depending on the capabilities of the hardware, you might be able to change the value stored in a variable more efficiently than evaluated a generic expression that reads from one variable, adds a constant, and stores it back into another variable. You might also have an instruction that is specifically intended to very efficiently increment the value stored in a variable.

So the C language provides three different forms so that the compiler writer can provide three different code generator segments to implement the appropriate instructions for each case. In essence, the language allows the programmer to be the pre-optimizer for the compiler.

Now, optimizing compilers are pretty capable at figuring out the optimal way to implement the correct semantics from the various options and carefully choosing which form to use may have little to no (or possibly even negative) benefit.
 

Thread Starter

MaxHeadRoom

Joined Jul 18, 2013
30,654
OK here is the (very) short program.
Max.
C:
/******************************************************************************
  DC_motor_xtal.c  - run a DC motor at xtal "clockwork" locked speed

  PIC16F628A - 20MHz HS xtal (see web page for schematic)
  Compiler - MikroC for PIC v8
  PIC pins;
   RA0 = digital ST input, quad encoder A
   RA1 = digital ST input, quad encoder B
   RB3 = CCP1 output, PWM to motor, HI = ON
   RB0 = echo encoder A output
   RB1 = echo encoder A output

   PIC configs; MCRLE off, BODEN off, BORES off, WDT off, LVP off, PWRT on
******************************************************************************/


#define  MOTOR_PULSE_PERIOD  6944444    // 1 RPS
#define  MOTOR_PROP_GAIN  10

// global vars
unsigned char rpos;       // reference position of xtal based freq
unsigned char mpos;       // actual motor position
unsigned char mlag;       // amount the motor lags the reference
unsigned char enc_new;    // holds motor's quadrature encoder data for testing
unsigned char enc_last;
unsigned long bres;       // bresenham accumulator used to make ref frequency
unsigned char pins;       // temporary var for echoing encoder signals


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void interrupt()
{
  //-------------------------------------------------------
  // This is TMR0 int, prescaled at 2:1 so we get here every 512 instructions.
  // This int does the entire closed loop speed control;
  //  1. updates encoder to see if motor has moved, records it position
  //  2. updates reference freq generator, records its position
  //  3. compares the two, sets PWM if motor lags behind reference
  //  4. limit both counts, so they never roll, but still retain all error
  //-------------------------------------------------------
  // clear int flag straight away to give max safe time
  INTCON.T0IF = 0;

  //  1. updates encoder to see if motor has moved, records it position
  enc_new = (PORTA & 0b00000011);   // get the 2 encoder bits
  if(enc_new != enc_last)
  {
    if(enc_new.F1 != enc_last.F0) mpos++;   // record new motor position
    else                          mpos--;
    enc_last = enc_new;
  }

  //  2. updates reference freq generator, records its position
  bres += 102400;                 // add nS per interrupt period (512 insts * 200nS)
  if(bres >= MOTOR_PULSE_PERIOD)  // if reached a new reference step
  {
    bres -= MOTOR_PULSE_PERIOD;
    rpos++;                       // record new xtal-locked reference position
  }

  //  3. compares the two, set PWM% if motor lags behind reference
  if(mpos < rpos)   // if motor lagging behind
  {
    mlag = (rpos - mpos);                            // find how far it's lagging behind
    if(mlag >= (100/MOTOR_PROP_GAIN)) CCPR1L = 100;  // full power if is too far behind
    else CCPR1L = (mlag * MOTOR_PROP_GAIN);          // else adjust PWM if slightly behind
  }
  else            // else if motor is fast, cut all power!
  {
    CCPR1L = 0;
  }

  //  4. limit both counts, so they never roll, but still retain all error
  if(rpos>250 || mpos>250)
  {
    rpos -= 50;
    mpos -= 50;
  }

}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


//=============================================================================
//   MAIN
//=============================================================================
void main()
{
  //-------------------------------------------------------
  // setup PIC 16F628A
  CMCON = 0b00000111;     // comparators OFF, all pins digital

  PORTA = 0b00000000;     //
  TRISA = 0b00000011;     // RA0,RA1 used for digital ST encoder inputs

  PORTB = 0b00000000;     //
  TRISB = 0b00000000;     // RB3 is CCP1 PWM out, RB0,RB1 are encoder echo outputs

  // set TMR2 to roll every 100 ticks, PWM freq = 5mil/16/100 = 3125 Hz
  T2CON = 0b00000111;     // TMR2 ON, 16:1 prescale
  PR2 = (100-1);          // PWM total period of 100

  // set PWM out on CCP1
  CCPR1L = 0;             // PWM range 0-100% = start  with PWM of 0%
  CCP1CON = 0b00001100;   // CCP1 on, set to PWM mode

  // TMR0 used for interrupt, makes interrupt every 512 insts
  OPTION_REG = 0b10000000;   // PORTB pullups OFF, TMR0 on, 2:1 prescale


  //-------------------------------------------------------
  // setup before main loop
  Delay_mS(200);    // allow PSU voltages time to stabilise

  // setup vars etc, will be used in interrupt
  bres = 0;
  rpos = 0;
  mpos = 0;

  // finally start TMR0 roll interrupt
  INTCON = 0b10100000;  // GIE=on, TMR0IE=on

  //-------------------------------------------------------
  // main run loop
  while(1)
  {
    //-------------------------------------------------
    // We don't need to do anything in main loop as the motor speed
    // control is done entirely in the TMR0 interrupt.


    //-------------------------------------------------
    // For convenience in setting up the encoder trimpots,
    // echo the two encoder pins out two spare PORTB digital outputs!
    pins = 0;
    if(PORTA.F0) pins.F0 = 1;
    if(PORTA.F1) pins.F1 = 1;
    PORTB = pins;    // output those two pins only (PWM output is not affected)
  }
 

philba

Joined Aug 17, 2017
959
It's up to the compiler to interpret it.
MikroC offers a listing file in assembler. It is not complete but is useful.

For me there is a difference between:
while(1)
and
while(1==1)
and
x=1;
while(x)

The compiler might "observe" that the condition is constant and provide an infinite cycle.
A half way competent compiler will optimize all of those down to the same machine code. Though the last one may not if x is assigned inside the while block or x is declared volatile or external. Though, if those are the only references (plus the declaration), any decent compiler will optimize away x. Heck, GCC does stuff like put variables into registers and completely eliminate the need for storage. Sure makes debugging confusing sometimes.
 
Top