This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Functions with multiple long params

I've created a little test program that runs fine in the simulator, but causes the hardware (80C390) to reset when a function with multiple long parameters is called. This is with v6.22. Am I missing something obvious? Running in the large memory model in a new project (I.E. all other settings as defaults.)

#include <REG390.H>
#include <absacc.h>

#include <stdio.h> 

void wait (void)  {                   /* wait function */
  int i;
  for (i=0;i<20000;i++)
  {
    ;
  }
}
void Serial0_Initialize(void)
{
  //  init serial interface 38400 baud @ 20MHz
  PCON  |= 0x80;   /* Double serial port 0 baud rate */
  SCON0  = 0x50;   /* Async receiver serial port 0 enable */	         
  TMOD  |= 0x21;   /* Timer 0 16 bits, Timer 1 8 bits with auto reload mode */        
  TH1    = 0xF8;   /* Load MSB of Timer 1 */
  CKCON |= 0x10;   /* Timer 1 clock select divide by 4 of xtal freq */
  TCON   = 0x50;   /* Timer 0 run enable, Timer 1 run enable */           
  TI     = 1;      /* Serial port 0 transmitter interrupt flag set */
}

unsigned char xdata* egdBufferGetInt(int buffer, int width, int height, int depth)
{
  unsigned char xdata *curBuf = 0;

  return curBuf;
}

unsigned char xdata* egdBufferGet(long buffer, long width, long height, long depth)
{
  unsigned char xdata *curBuf = 0;

  return curBuf;
}

long egdDrawInt(unsigned char xdata *buffer, int width, int height)
{
  ;
}

long egdDraw(unsigned char xdata *buffer, long width, long height)
{
  ;
}

void main (void)
{
  unsigned char xdata *b;

  // Initialize serial port 0
  Serial0_Initialize();
  printf("Serial initialized!\n");
  wait();

  printf("Trying BufferGetInt...\n");
  b=egdBufferGetInt(0, 320, 240, 1);
  printf("BufferGetInt success\n");
  wait();

  printf("Trying BufferGet...\n");
  b=egdBufferGet(0, 320, 240, 1);
  printf("BufferGet success\n");
  wait();

  printf("Trying Draw Int...\n");
  egdDrawInt(b, 320, 240);
  printf("Draw Int success\n");
  wait();

  printf("Trying Draw...\n");
  egdDraw(b, 320, 240);
  printf("Draw success\n");
  wait();

  while (1)
  {
    printf("Waiting...\n");
    wait();
  }
}

Here is the output from the serial port:
Serial initialized!
Trying BufferGetInt...
BufferGetInt success
Trying BufferGet...
 erial initialized!
Trying BufferGetInt...
BufferGetInt success
Trying BufferGet...
 erial initialized!
Trying BufferGetInt...
BufferGetInt success
Trying BufferGet...
 erial initialized!
Trying BufferGetInt...
BufferGetInt success
Trying BufferGet...
 erial initialized!

  • I am also having reset problems with my huge memory model. I can not track down what is causing it. Please let me know what you find out. My resets come and go as I recompile the program. If I make any progress I will let you know.
    Paul Davis

  • Could the watchdog timer be causing these problems?

    Jon

  • If I shift the exact program by 1 byte the resets stop. I am 99.9% sure that the watch dog is being correctly used.

  • Hmmmm,

    Since you're using the 251 and Kevin is using the 390, I doubt if these two problems are related.

    Jon

  • I notice that the parameters to egdBufferGet are constants, but not specifically longs:

    b=egdBufferGet(0, 320, 240, 1);
    
    Have you tried:
    b=egdBufferGet(0L, 320L, 240L, 1L);
    
    It's just a thought...

  • I wouldn't guarantee I tried making them all longs for this particular example, but I have tried it on others, without any help.

    In fact, I've noticed even making more than 2 local variables longs with a function that takes a long usually causes problems.

    I'm not setting up the watchdog, so that shouldn't be a problem either.

    We are planning on moving to the contiguous memory model anyway, so I hope this problem will go away there, but I haven't tested that theory yet.

    Unfortunately I don't have any hardware other than the 80C390 to test on.

  • Can you try it in v6.14 of the compiler?

    I know that the "upgrade" from v6.14 to v6.20 broke one of my functions with long parameters, although v6.22 has fixed that particular problem for me.

  • Unfortunately no, since we just recently purchased the compiler.

    I'd be curious if the test program runs on other hardware fine, since it runs in the simulator fine...

  • Hmm... two long args (8 bytes) causes problems. Interesting that passing two longs in registers would require the entire register bank. I wonder if there is a "spill over" bug. When a stack frame cannot fit into the arg. regs. then they must spill over into a stack frame memory area.

    In the short term, you might create a suitcase union of structs such that you have in it structs for both long an int vars and a type field. Then have one function that looks at the type field and does the correct work.

    Or you could write a var_args function and make your function work like printf which does work.

    - Mark

  • What happens when you call egdBufferGet first?

    What happens if you also put a printf statement in egdBufferGet?

  • > What happens when you call egdBufferGet first?

    It always dies on that call, no matter when it is called.

    > What happens if you also put a printf statement in egdBufferGet

    It never prints out anything in the egdBufferGet() function.

  • One of the differences for the caller/callee of your functions with the long parameters as opposed to those with int parameters, is that the long versions pass the parms on the external memory "stack", whereas the int versions pass the parms in R0-R7. Are there any START390.A51 aspects that need to be configured for running on your target hardware that you are getting away with not configuring when simulating?

  • Possibly. (I'm new to the hardware.)


    However, I'm able to successfully call a function with 8 integer params, which should use the same amout of param space as 4 longs...

  • "it runs in the simulator fine..."

    Probably not the same thing then; in my case, the compiler was definitely generating bad code - the fault could be seen on both target and simulator.

  • OK, interesting. The difference now is that the int version of the call uses MOVX @DPTR to directly store the parms into XRAM, whereas the the long version uses the library function ?C?LSTKXDATA, which pops the return address into DPTR, copies the constant parms out of the code memory locations that immediately follow the call, advancing DPTR along the way, then returns "through" the DPTR (i.e., JMP @A+DPTR) to the instruction immediately following the constant parms. I'm familiar with some Dallas MCU's, but not the '390. Aren't there some considerations for DPTR-related instructions when dealing with code memory? I wonder if something is slightly askew in this area.