Shop OBEX P1 Docs P2 Docs Learn Events
PASM sign extend (+ a few other questions)? — Parallax Forums

PASM sign extend (+ a few other questions)?

MicrocontrolledMicrocontrolled Posts: 2,461
edited 2014-01-14 06:49 in Propeller 1
I've written a fairly long PASM code that reads through a bytecode script and executes routines according to the script. For several of routines it needs to read a portion of the script as a 9-bit 2's compliment signed integer. Though it reads the integer correctly if it is positive, if a negative number is given (for example %111110110) it will read it as a positive number because the size of the register extends it to %000000000000000000000000111110110 and doesn't see it as negative. I cannot think of an efficient way to "sign extend" the register to read it as a negative, without using the "neg" command which will change the intended integer.

Also, there is another part of the code that only works when I change a portion of SPIN code running in another cog, completely unrelated to this PASM code entirely, from "variable++" to "variable +=2". Though this variable is linked to the PASM script, the portion of SPIN code it is in is bypassed and not even run. I'll post the code if needed, but it's not very neat and I haven't finished commenting it yet. Plus, the fact this function isn't even used yet still affects the code makes me think it doesn't have to do with the PASM code itself.

And one more question, since I am a bit of a n00b to PASM specifically, when you shift bits, do they get shifted into the next (or previous) corresponding register, or are they just removed?

Thanks :)

Comments

  • Dave HeinDave Hein Posts: 6,347
    edited 2014-01-13 08:08
    You can sign-extend a value by shifting left by (32-N) bits, and use SAR to do an arithmetic shift right by (32-N) bits.

    A shift instruction will put the first bit in the carry bit if you specify WC, and throw away all the other bits that are shifted out.

    The ++ operator does the same function as +=1. If you want to do +=2 you would need to execute ++ twice. So if your code is only doing it once that might be the problem. If your code is doing ++ twice, then you may have a problem with scribbling into memory. This can be cause by using a bad pointer, or a stack that is too small.
  • Mark_TMark_T Posts: 1,981
    edited 2014-01-13 08:39
    Yes, the shift method is pretty standard, ie
                    SHL   val, #23
                    SAR   val, #23
    
    But there are many ways to do this, MUXNZ will do nicely for instance:
                    TEST  val, #$100  wz   ' test sign bit to Z flag
                    MUXNZ val, HFFFFFE00  ' mux into other top bits
    
    HFFFFFE00       long  $FFFFFE00
    
    Or the very pedestrian test and subtract:
                    TEST  val, #$100  wz   ' test sign bit to Z flag
             if_nz  SUB   val, H200  ' subtract 2^9
    
    H200            long  $200
    

    (Hopefully I've not made any mistakes, but I'd double check just in case)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-01-13 10:13
    Dave Hein wrote:
    The ++ operator does the same function as +=1.
    Not really, since the OP referred to the postincrement variety. For example,
      x := 5
      sio.dec(x += 1)
    

    outputs 6, while
      x := 5
      sio.dec(x++)
    
    outputs 5. But
      x := 5
      sio.dec(++x)
    

    will output 6.


    -Phil
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-01-13 10:24
    Phil, without seeing Microcontrolled's code we'll never know if it was being used that way. There are a million ways his code could be failing. I was just suggesting a couple of possible explanations. Clearly, ++ and +=2 don't give the same result. Also, he said the code is not even used yet, so it's difficult to determine what impact it is having. Generally, if you modify "unused" code and it changes how a program runs that indicates that the program is sensitive to the location of data. This usually indicates that the program is using an uninitialized variable or it's scribbling in memory.

    Microcontrolled, please post your code.
  • MicrocontrolledMicrocontrolled Posts: 2,461
    edited 2014-01-13 10:33
    I'm aware that += 2 will increment by two whereas ++ will increment by one, but the point is that they are not effecting anything in the PASM code. The code starts the PASM cog, waits for half a second (the process completes in less than a few milliseconds, so it's done running) then waits for user input. If user input in detected, it increments a counter by one with variable++. What I found was that if I changed the code to step by 2 each time user input was detected (using variable += 2) a troublesome piece of the assembly code that previously didn't work suddenly started working as intended. Keep in mind that the assembly code ran to completion BEFORE this spin code function is even used.
  • MicrocontrolledMicrocontrolled Posts: 2,461
    edited 2014-01-13 10:37
    Here is the code in question. The "Branch" routine is the part that works/doesn't work depending on the incrementing of the "stepper" variable. The rest of the code seems to work ok, though the PASM is far from optimized.
    LC3.spin
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-01-13 11:12
    Dave Hein wrote:
    Phil, without seeing Microcontrolled's code we'll never know if it was being used that way.
    Also, there is another part of the code that only works when I change a portion of SPIN code running in another cog, completely unrelated to this PASM code entirely, from "variable++" to "variable +=2".

    True, we don't know whether it was being used in an expression; but regardless, in the general case x++ is still not the same as x += 1, whereas ++x is.

    -Phil
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-01-13 11:15
    Micro,

    You've got:
      startAddress := @fal
      
      cognew(@StartLC3,[b]@[/b]startAddress)
    

    I think you mean:
      startAddress := @fal
      
      cognew(@StartLC3,startAddress)
    

    -Phil
  • MicrocontrolledMicrocontrolled Posts: 2,461
    edited 2014-01-13 11:40
    Actually I think the original code is right, as PC needs to be loaded with the address of the script. The code is labeled "fal", so startAddress := @fal will store the address of the script, then @startAddress will push the address of the variable storing the address to fal into PAR, which is then read with rdlong into PC. If my train of logic is correct (and it may not be!) this should load PC with the address of "fal", right? I did try it the other way, and it didn't run the script. I could be completely off here, as this is the first "serious" code I've written in PASM, so let me know if there is a problem in my reasoning. Thanks!
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-01-13 12:17
    True, we don't know whether it was being used in an expression; but regardless, in the general case x++ is still not the same as x += 1, whereas ++x is.
    Thanks, Phil. Since you're a moderator maybe you can help add more emoticons to the forum. I can't seem to find a "nit-picking" emoticon. :)
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-01-13 12:29
    One problem you might encounter is something that I've run into recently. The variable fal is word-aligned. The PAR register can only hold long-aligned address because the 2 LSBs are zero. So it's possible for the two LSBs of @fal to be 10, but they will be passed as 00 through PAR. This would cause the address in PAR to be 2 bytes before the intended address. You should be OK in the sample of code you posted since fal follows PASM code, which is long-aligned.

    EDIT: I'm confused by the first few instructions in your PASM code. Shouldn't the PC be set to the value of PAR instead of the contents of the long pointer to by PAR. That is, the PC should be @fal, and not long[@fal] correct?
  • kuronekokuroneko Posts: 3,623
    edited 2014-01-13 18:24
    A few observations:
    mainLoop               rdword  cInst, PC              'Read the current instruction from RAM
                           add     PC, [COLOR="#FF0000"]#2[/COLOR]                 'Increment the program counter
    
    As we have word granularity we need an increment of two. The test program doesn't show this but you'll notice when you increment a register which will then happen twice.
    imm5clear long    %11111111111111111111111000000000    'I never call this data, but for some reason if I remove it the program stops working
    
    The existence of this extra long determines whether the branch in your test program is taken or not. This is down to a faulty condition check in the branch subroutine. At this point DR (holding the exec condition) is already destroyed (*2+base) IOW the outcome is highly code position dependent.
    'Isolate DR
           mov       DR, cInst              'Obtain DR from the instruction
           mov       addSub, opCode         'Make addSub opCode in format xxxx
           shl       addSub, #12            'Turn xxxx to xxxx000000000000
           sub       DR, addSub             'Clear this making 0000xxx000000000
           shr       DR, #9                 'Shift to make it 0000xxx  (END OF PROCESS)
    
    May I suggest (this also applies to the remaining parameters):
    'Isolate DR
           mov      DR, cInst
           shr      DR, #9
           and      DR, #%111
    
  • MicrocontrolledMicrocontrolled Posts: 2,461
    edited 2014-01-14 06:49
    @kuroneko: THANK YOU! Those were the problems, I can't believe the program ran correctly with PC being off, but this explains the strange results I would get in R0. I moved the DR modification routines after the tjz command that calls the branch routine, and that fixed it, everything seems to be in working order now. I'm also using AND in my sorting functions instead of subtracting, and it's saving me a lot of code. I'm not sure why I didn't think of that sooner. Thanks again!
Sign In or Register to comment.