Shop OBEX P1 Docs P2 Docs Learn Events
@Bean, STACK issues — Parallax Forums

@Bean, STACK issues

Peter VerkaikPeter Verkaik Posts: 3,956
edited 2009-02-17 16:29 in General Discussion
Bean,
I was trying to use manual banking to access stack variables.
The attached program tries to calculate signed division using
2 FUNC's with local variables.

FUNC imSDIV16
  imLocal var byte (1)
  imSign  var byte @imLocal(0)
  bank @imLocal 'use #__STACK and the stackbank is accessed, imSign @$2F
  imSign = __param2 XOR __param4
  __wparam12 = abs __wparam12   'make values positive
  __wparam34 = abs __wparam34
  imUDIV16 __param1,__param2,__param3,__param4
  bank @imLocal 'use #__STACK and the stackbank is accessed
  if imSign.7 = 1 then
    __wparam12 = - __wparam12
    __wparam34 = - __wparam34
  endif
  bank __DEFAULT
  return 'prevents warning
ENDFUNC

FUNC imUDIV16
  imLocal var byte (4)
  imAccuA var word @imLocal(0)
  imAccuB var word @imLocal(2)
  bank @imLocal 'use #__STACK and the stackbank is accessed, imAccuB_MSB at $2F
  imAccuB = __wparam34
  imAccuA = __wparam12 / imAccuB
  __wparam34 = __wremainder  'save the remainder
  __wparam12 = imAccuA
  bank __DEFAULT
  return 'prevents warning
ENDFUNC

The declaration of locals is straight forward.
The list output shows

   198  =0000003B       imSDIV16:                        ;FUNC imSDIV16
   199                  
   200  =0000001F       imLocal      = __STACK-$01       ;  imLocal var byte (1)
   201  003B  0C01        ADD __STACKPTR,#1             
        003C  01EF
   202                  
   203  =0000001F       imSign        =  imLocal+0       ;  imSign  var byte @imLocal(0)
   204                  

   260  =0000006B       imUDIV16:                        ;FUNC imUDIV16
   261                  
   262  =0000001C       imLocal      = __STACK-$04       ;  imLocal var byte (4)
   263  006B  0C04        ADD __STACKPTR,#4             
        006C  01EF
   264                  
   265  =0000001C       imAccuA       =  imLocal+0       ;  imAccuA var word @imLocal(0)
   266  =0000001C       imAccuA_LSB   =  imAccuA        
   267  =0000001D       imAccuA_MSB   =  imAccuA+1      
   268                  
   269  =0000001E       imAccuB       =  imLocal+2       ;  imAccuB var word @imLocal(2)
   270  =0000001E       imAccuB_LSB   =  imAccuB        
   271  =0000001F       imAccuB_MSB   =  imAccuB+1      
   272                  

So the addresses of the declared locals are outside the stackbank (which·is at $20).
So I thought, lets use bank @__STACK to gain access to the stackbank.
That works, except that imAccuB_MSB has the same address as imSign,
so when imUDIV16 is called, imSign gets overwritten.

Then I remembered that we need to calculate the true addresses, using
· w = @imLocal
· fsr = w
This selects the stackbank.
However, calling UDIV16, imAccuB_MSB still overwrite imSign.

Now, how can we prevent that from happening while imAccuB_MSB and imSign
have the identical offset to their local top of stack.

regards peter

Comments

  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2009-02-17 15:39
    One solution I can think of
    is by declaring skipbytes like this

    FUNC imUDIV16
      imSkip  var byte (1)
      imLocal var byte (4)
      imAccuA var word @imLocal(0)
      imAccuB var word @imLocal(2)
      w = @imLocal
      fsr = w
      'bank @imLocal 'use #__STACK and the stackbank is accessed, imAccuB_MSB at $2F
      imAccuB = __wparam34
      imAccuA = __wparam12 / imAccuB
      __wparam34 = __wremainder  'save the remainder
      __wparam12 = imAccuA
      bank __DEFAULT
      return 'prevents warning
    ENDFUNC
    
    

    which skips the amount of bytes already allocated from stack
    when entering imUDIV16. In this case the number is 1,
    but in general, the number must be equal to the deepest
    level at which imUDIV16 is called (it may also be called from
    another sub that uses 3 localbytes, in which the skipbytes must be set to 3).
    That really is not a workable solution because one has to trace the calls.
    Besides that, it makes us run out of locals much quicker.

    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2009-02-17 16:03
    This works, (instead of calling imUDIV16 we call imUDIV16_2)

    FUNC imUDIV16_2
      imAccuA var word
      imAccuB var word
      imAccuB = __wparam34
      imAccuA = __wparam12 / imAccuB
      __wparam34 = __wremainder  'save the remainder
      __wparam12 = imAccuA
      bank __DEFAULT
      return 'prevents warning
    ENDFUNC
    
    

    but then accessing the locals takes quite more code,
    so that's why I tried to use manual banking, but it looks
    impossible to make that happen.

    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2009-02-17 16:29
    I took the generated code from that last function
    and inserted it as asm, removing unnecessary instructions.
    It turns out·imAccuB is not required when directly using asm.

    FUNC imUDIV16_2
      imAccuA var word
    asm
     MOV W,#imAccuA ;  imAccuA = __wparam12 / __wparam34
     ADD W,__STACKPTR
     MOV FSR,W
     CLR IND
     INC FSR
     CLR IND
     DEC FSR
     MOV W,__PARAM3
     OR W,__PARAM4
     JZ @$+42
     CLR __PARAM5
     JMP @$+5
     CLC
     RL __PARAM3
     RL __PARAM4
     INC __PARAM5
     JNB __PARAM4.7,@$-4
     JMP @$+9
     CLC
     RL IND
     INC FSR
     RL IND
     DEC FSR
     RR __PARAM4
     RR __PARAM3
     SETB IND.0
     SUB __PARAM1,__PARAM3
     MOV W,__PARAM4
     SC
     MOV W,++ __PARAM4
     SUB __PARAM2,W
     JC @$+10
     CLRB IND.0
     ADD __PARAM1,__PARAM3
     ADDB __PARAM2,C
     ADD __PARAM2,__PARAM4
     DJNZ __PARAM5, @$-24
    endasm
      __wparam34 = __wremainder  'save the remainder
      __wparam12 = imAccuA
      return 'prevents warning
    ENDFUNC
    
    

    This looks the best I can get.

    regards peter
Sign In or Register to comment.