Shop OBEX P1 Docs P2 Docs Learn Events
Stuck on ASM problem :RESOLVED THANKS TO ALL — Parallax Forums

Stuck on ASM problem :RESOLVED THANKS TO ALL

WurlitzerWurlitzer Posts: 237
edited 2008-02-25 19:22 in Propeller 1
The following code snippit works fine if I have 2 (or more)·instructions inserted where shown. The instruction type does not seem to matter as even NOPs work.

This routine should use data read·out of a circular queue (it does) and eventually jump to some code to write a long to the hub ram and does if I have these 2 (or more) instructions added. If I remark them out, nothing is written to the hub ram.

The "CALL #TestWrite" does work as I can see the another HUB ram location change to the expected value.

My guess is that somehow the JMP to "StatusJumpTbl" gets screwed up without the 2 added instructions.

The address in the cog of the StatusJumpTbl is $1F (the address is $1D without the added instructions).

For testing,·the value of tmp_z is $0B (before it is added to the StatusJumpTbl address) and should force a jump to "ControllerCmd" which it does if
I have the··extra instuctions where shown.

If I just place 2 extra NOPs in the same location, then do a call #testwrite from the routine at "ControllerCmd" I get a value of $20 which is exactly what it should be. $0B-$0A = 1 plus the StatusJumpTbl address of $1F = $20. If the extra code is not present then it seems like "ControllerCmd" is
never jumped to.
ParseQueData
                        mov     DataByte2_z, QueReadData_Lng
                        and     DataByte2_z, #$FF     'strip off everything except LSbyte         
                        mov     StatusByte_z,QueReadData_Lng
                        shr     StatusByte_z, #16
                        mov     tmp_z, StatusByte_z
                        shr     tmp_z, #4       'removes Channel Nibble
                        and     tmp_z, #$0F
'FOR SOME REASON I NEED 2 (OR MORE) INSTRUCTIONS BELOW. EVEN 2 NOPs WORK. WHY?                        
                        mov     loopcounter, tmp_z 'REMOVE
                        call    #testwrite'REMOVE
                        
                        cmp     tmp_z, #$0A wc,wz,nr
              if_b      jmp     #MainLoop_z     'if < $0A then jump to main loop
                        cmp     tmp_z, #$0F wc,wz,nr
              if_a      jmp     #MainLoop_z      'if > $0F then jump to main loop
                        sub     tmp_z, #$0A wc,wz'$0A points to the first entry in table. 
                        add     tmp_z, #StatusJumpTbl
                        jmp     tmp_z  'jump to statusJumpTbl based upon value of StatusByte
                        
'===================================================================================                        
StatusJumpTbl
                        jmp     #MainLoop_z             '$Ax NOT USED Aftertouch
                        jmp     #ControllerCmd          '$Bx Controller
                        jmp     #ChannelMessage         '$Cx Program change
                        jmp     #mainLoop_z'            '$Dx NOT USED  Channel pressure
                        jmp     #mainLoop_z             'NOT USED'$Ex Pitch wheel   Transposer values
                        jmp     #sysCommand_z             '$Fx System command

Post Edited (Wurlitzer) : 2/24/2008 3:25:27 PM GMT
«1

Comments

  • hippyhippy Posts: 1,981
    edited 2008-02-19 16:55
    When using IF_B and IF_A conditional execution I've always used signed compares ( cmps ) ... don't
    know if I need to but it's something worth trying. I cannot see any reason why it wouldn't work or why
    adding extra 'nop' instructions make it work.
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-19 17:29
    Hippy: You are probably right on using CMPS. I did change the compares to CMPS however the extra instructions are still needed.

    Thanks for looking at the code.
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-19 18:01
    Ok! I see the problem source seems to be timing after a RDLONG even though I seem to have sufficient code after the RDLONG before I do anything with the· destination·variable "QueReadData_Lng, ·HOWEVER, I may be overwriting the source address for the RDLONG. Can that happen while waiting for the Cog to sync with the HUB????????

    I knew I had to wait 7-22 cycles to assure the validity of the returned data but overlooked (possibly) playing with the address of the RDLONG instruction prior to the 7-22 cycles. This would make sense!

    HOWEVER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    If that is the case, why would adding NOPs ·much further down in the code also work? From the RDLong I have 5 lines of code (minimum) prior to hitting the "ParseQueData" routine then 7 more instructions before I had added the extra code in my original post?

    I just kept moving the extra NOPs further up stream until the code no longer functioned.

                            call    #ReadQue        'Data is in the circular Queue read it
    

                            call    #ParseQueData   '
    '                       call    #WriteParsedData
                            jmp     #MainLoop_z
    '==============================================================================================
    ReadQue
                            rdlong  QueReadData_Lng,CurrentQueHeadCtr
    

    
    
    'IF I ADD 2 NOPs HERE THE CODE WILL WORK! THIS SEEMS TO BE THE ACTUAL SOURCE OF THE PROBLEM! IS THE ADDRESS BEING OVER'WRITTEN BEFORE THE COG SYNCS WITH THE HUB? IF SO WHY WOULD EXTRA NOPs WORK WHEN ADDED SOME 12 OR MORE INSTRUCTIONS LATER
    

                            add     CurrentQueHeadCtr, #4              'make ready for next read
                            cmp     CurrentQueHeadCtr, QueBufferEnd wz,wc,nr 'is this past the end of the circular queue?
                  if_be     jmp     #ReadQue_ret                        
                            mov     CurrentQueHeadCtr, QueBufferStart  'point to start of circular queue                        
    ReadQue_ret             ret
    '=================================================================================================
    ParseQueData                        mov     DataByte2_z, QueReadData_Lng
                            and     DataByte2_z, #$FF     'strip off everything except data byte 2         
                            mov     StatusByte_z,QueReadData_Lng
                            shr     StatusByte_z, #16
                            mov     tmp_z, StatusByte_z
                            shr     tmp_z, #4       'removes Channel Nibble
                            and     tmp_z, #$0F
    'FOR SOME REASON I NEED 2 INSTRUCTIONS HERE. EVEN 2 NOPs WORK. WHY?                        
                             'nop
                            'nop
                            cmps     tmp_z, #$0A wc,wz,nr
                  if_b      jmp     #MainLoop_z     'if < $0A then jump to main loop
                            cmps     tmp_z, #$0F wc,wz,nr
                  if_a      jmp     #MainLoop_z      'if > $0F then jump to main loop
                            sub     tmp_z, #$0A wc,wz'$
    

                            add     tmp_z, #StatusJumpTbl
                            jmp     tmp_z  'jump to statusJumpTbl based upon value of StatusByte
    

    '===================================================================================                        
    StatusJumpTbl
                            jmp     #MainLoop_z''$Ax NOT USED Aftertouch
                            jmp     #ControllerCmd          '$Bx Controller
                            jmp     #ChannelMessage         '$Cx Program change
                            jmp     #mainLoop_z''$Dx NOT USED  Channel pressure
                            jmp     #mainLoop_z'NOT USED'$Ex Pitch wheel   Transposer values
                            jmp     #sysCommand_z             '$Fx System command
    
  • Mike GreenMike Green Posts: 23,101
    edited 2008-02-19 18:21
    Your explanation doesn't make sense. The RDLONG (and other hub instructions) stops the processor until the cog gets an access. This cog just sits there if necessary. Other cogs may continue, but this one stops at the RDLONG. The source address can't be overwritten since it's in a cog memory location and is not accessible to other cogs.

    Does it make a difference that ReadQue returns sometimes and doesn't return at other times (jumps to mainLoop_z)? There's no stack, so the fact that ReadQue_ret is overwritten on the next call shouldn't matter.

    Could the problem be one of code positioning rather than timing? By having two instructions, the following code is displaced forward in memory by two long words.
  • hippyhippy Posts: 1,981
    edited 2008-02-19 19:46
    I cannot see anything wrong. The tmp_z compare for greater than $0F is redundant because you've
    already anded that with $0F earlier. The 'cmp' before 'if_be' for adjusting the queue pointer might
    also benefit from being a 'cmps'.

    Is it worth posting your entire code in case it's something elsewhere we are not seeing which is having
    an effect on behaviour ? Not that I can see any obvious reason why adding the NOP's fixes whatever
    problem there is. Do they really fix the problem, or is that simply masking whatever's actually going
    wrong ?
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-19 20:23
    Mike! The ReadQue_Ret should get hit·at the end of·every ReadQue call. Sometimes I jump to it other times I need to reset the pointer to the head of the Circular Queue.

    Thanks for the insite on how the COG waits as I was unsure if I played with the address before the RDLONG finished what would happen. Based upon your reply I do not have to be concerned as nothing happens until the RDLONG is finished.

    The strange thing is the value read from the RDLONG is correct regardless if the rest of the code is working or not. I can see that in the HUB Ram.

    Thank you for taking the time to look at the code.
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-19 20:50
    Mike wrote:

    "Could the problem be one of code positioning rather than timing? By having two instructions, the following code is displaced forward in memory by two long words."

    Good thought! That is why I verified the JMP to StatusJumpTbl addressing. It seemed correct!

    While I believe every variable in this assembly routine has been declared as a long, your comment merits some investigation. I would expect strange results like this·if I had not been careful with declaring bytes at improper boundaries.

    ·I will play with the number of inserted instructions to see if there is a pattern. I have tried 1,2,3 and 1 does not work but 2 or 3 does.

    This assembly routine is one of 2 in the same SPIN file if that makes any difference. I have checked for declaration conflicts and different entry points etc. SIDE COMMENT: Is there any way to have just assembly code in its own file rather than some SPIN calling 1 or more assembly routines. I understand the need for at least one spin routine but I would like separate files for pure assembly.

    Mike & Hippy let me play with this some more and if I cannot spot the issue, I'll post the code. As it is under development I would want to add comments as to where the functioning code ends and the under development starts. Right now I just plant a bunch of JMP #MainLoop_z around to bypass the under development code.

    Thanks again to both of you for taking the time to review this.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-02-19 20:56
    The only way to put the assembly code in its own file is to put it into an object and that may not be what you want, particularly if you refer to the assembly code from other places (like Spin methods). I think that the compiler requires at least one Spin method in an object since there's no way to execute or refer to the assembly code without that.

    The compiler will align items to their proper boundaries with instructions on long word boundaries.

    It may well be that there's an error in the assembly code that you left out, but it's manifesting itself in what you've shown.
  • KaioKaio Posts: 253
    edited 2008-02-19 22:52
    Wurlitzer,

    only a suggestion: You could optimize your code easily to have a deterministic execution time of ReadQue. This would perhaps avoid unnecessary waiting on RDLONG.

    ReadQue
                            rdlong  QueReadData_Lng,CurrentQueHeadCtr
                            add     CurrentQueHeadCtr, #4              'make ready for next read
                            cmp     CurrentQueHeadCtr, QueBufferEnd wz,wc,nr 'is this past the end of the circular queue?
    '              if_be     jmp     #ReadQue_ret                       'not necessary if you would use an opposed condition on the next statement
                 if_a       mov     CurrentQueHeadCtr, QueBufferStart  'point to start of circular queue
    ReadQue_ret             ret
    
    



    Did you have used any assembly debugger to analyse your trouble?

    Thomas
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-20 06:50
    I think that I am having a similar problem. Have a look in this thread http://forums.parallax.com/showthread.php?p=707333
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-20 07:59
    I have no idea if this is your problem, however when I see:

         add tmp_z, #foo
         jmp tmp_z
    
    



    I wonder if maybe the JMP instruction has been pre-fetched into the pipeline and maybe tmpz has as well, so you've got a stale version of tmpz in addition to the jump. That would suggest that adding a nop between the add and the jmp should make it reliable but I've not tried that.

    --Chuck
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-20 08:03
    I believe that the first thing that is put into the pipeline is the instruction and then the source and destination registers are read. So you have to be careful if you are changing the instruction but not the destination or the source. So that shouldn't be the problem.
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-20 08:23
    Right, Steven smile.gif Also, refer to the corresponding Sidetrack in my Tutorial...
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-20 08:42
    deSilva said...
    Right, Steven smile.gif Also, refer to the corresponding Sidetrack in my Tutorial...
    Thats where I checked first. smile.gif Some of us do read it smile.gif
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-22 13:10
    Again I thank everyone for taking the time to look at this code! I have tried numerous things but keep coming back to adding 2 NOPs after the read long instruction. It is getting to the point of leaving it in however all that means is I have a flaw in my understanding of the assembly language and sooner or later it will be repeated.

    The insertion of the 2 NOPs is now located in the ReadQue routine on the 2nd and 3rd lines right after the rdlong instruction. All my testing seems to point to the an improper jump to the #StatusJumpTbl near the bottom of the ParseQueData routine if these added instructions are not in the program.

    I have read the tutorial numerous times but, while very helpful, I obviously have not picked up on my error. There also seems to be 2 schools of thought, based upon some responses, as to what cautions need to be taken immediately after a HUB based instruction. At this point the code runs so fast I am not dwelling on perfect optimization.



    DAT
                  org  
    entry_z
                            call      #Initialize_ParseMidi
    MainLoop_z
                            rdlong  CurrentQueTailAddr,QueTailPtrAddr 'read location of current queue tail address
                            cmp     CurrentQueTailAddr,CurrentQueHeadCtr wc,wz,nr 'if different read current head value
                  if_e      jmp     #MainLoop_z   'Working:no new data go back to main loop
                            call    #ReadQue        'Working: data waiting to be read
                            call    #ParseQueData   '
    '                       ' call    #WriteParsedData
                            jmp     #MainLoop_z
    '==============================================================================================
    ReadQue
                            rdlong  QueReadData_Lng,CurrentQueHeadCtr
                            nop      'ADDED CODE TO FIX UNKNOWN PROBLEM
                            nop      'ADDED CODE TO FIX UNKNOWN PROBLEM
                            add     CurrentQueHeadCtr, #4              'make ready for next read
                            cmp     CurrentQueHeadCtr, QueBufferEnd wz,wc,nr 'is this past the end of the circular queue?
                  if_be     jmp     #ReadQue_ret                        
                            mov     CurrentQueHeadCtr, QueBufferStart  'point to start of circular queue                        
    ReadQue_ret             ret
    '=================================================================================================
    ParseQueData
                            mov     DataByte2_z, QueReadData_Lng
                            and     DataByte2_z, #$FF     'strip off everything except data byte 2         
                            mov     StatusByte_z,QueReadData_Lng
                            shr     StatusByte_z, #16
                            mov     tmp_z, StatusByte_z
                            shr     tmp_z, #4       'removes Channel Nibble
                            and     tmp_z, #$0F
                            cmps     tmp_z, #$0A wc,wz,nr
                  if_b      jmp     #MainLoop_z     'if < $0A then jump to main loop
                            cmps     tmp_z, #$0F wc,wz,nr
                  if_a      jmp     #MainLoop_z      'if > $0F then jump to main loop
                            sub     tmp_z, #$0A wc,wz'
                            add     tmp_z, #StatusJumpTbl
                            jmp     tmp_z  'jump to statusJumpTbl based upon value of StatusByte
    '===================================================================================                        
    StatusJumpTbl
                            jmp     #MainLoop_z''$Ax NOT USED Aftertouch
                            jmp     #ControllerCmd          '$Bx Controller
                            jmp     #ChannelMessage         '$Cx Program change
                            jmp     #mainLoop_z''$Dx NOT USED  Channel pressure
                            jmp     #mainLoop_z'NOT USED'$Ex Pitch wheel   Transposer values
                            jmp     #sysCommand_z             '$Fx System command
    '==================================================================================                        
    :ChannelMessage         jmp #mainLoop_z 'Add if needed
    '=============================== Control Message =================================
    'Parse out Swell (B0_07_dd) or Transposer messages (B0_07_dd) then handle stop/piston messages
    ControllerCmd           '$Bx received
                            mov     tmp_z,QueReadData_Lng
                            shr     tmp_z,#8                'strip off byte 0
                            cmp     tmp_z, SwellCmdMsg wc,wz,nr      '$B0_07_xx
                  if_e      jmp     #SwellMessage
                            cmp     tmp_z, TransposeCmdMsg wc,wz,nr '$B0_06_xx
                  if_e      jmp     #TransposeCmd
    'Not a Swell or Transpose Command process further
                            jmp #mainloop_z'REMOVE
                            mov     tmp_z, StatusByte_z
                            and     tmp_z, #$0F             'leaves Channel #. This is used to set the
                                                            'appropriate bit
                            mov     StopHubBytePntr, StopOffset        'StopOffset is starting address of stops in Hub
                            add     StopHubBytePntr, DataByte2_z         't1_z = Address in Hub for this stop byte
     'NOTE METHOD TO READ JUST A BYTE NEEDED
                            mov     StopTablePtr, #tblStopMsg0 'First byte address in table
                            add     StopTablePtr, DataByte2_z  'Point to proper table btye
                            movs    ReadStopTable, StopTablePtr
                
    ReadStopTable           mov     StopTableValue, 0-0     '0-0 is replaced by the table address         
    '              muxc outa, OutPinPointer
                  
                           jmp #mainLoop_z'REMOVE TEST ONLY                         
                           ' jmp     #ControllerJmpTbl
         
    sysCommand_z
                 'Needs to be written           
    ParseQueData_ret
                           
    WriteParsedData         'Needs to be written
                            nop
    WriteParsedData_ret     ret
    TransposeCmd            '$B0_06_xx
                            wrbyte  DataByte2_z, TransposerAddr_z
                            jmp     #MainLoop_z    'Done
    SwellMessage            '$B0_07_xx
                            wrbyte  DataByte2_z, SwellAddr_z
                            jmp     #MainLoop_z    'Done
                                                   
     testwrite  'REMOVE TEST ONLY                        
                          wrlong    loopcounter,QueHeadPtrAddr'REMOVE TEST ONLY
                           nop
                           nop                    
     testwrite_ret          ret     'REMOVE TEST ONLY       
    Initialize_ParseMidi
                            mov     QueBufferStart, par
                            add     QueBufferStart,QueBufferStartOffset  'adds the hub starting addr to the buffer start
                            mov     QueBufferEnd, par
                            add     QueBufferEnd,QueBufferEndOffset  'adds the hub starting addr to the buffer end
                            mov     QueHeadPtrAddr,par
                            add     QueHeadPtrAddr, QueHeadPtrAddrOffset  'points to loc in Hub ram for current head address
                            mov     QueTailPtrAddr,par
                            add     QueTailPtrAddr, QueTailPtrAddrOffset  'points to loc in Hub ram for current head address
                            mov     TransposerAddr_z,par
                            add     TransposerAddr_z, iniTransposerOffset
                            mov     SwellAddr_z, par
                            add     SwellAddr_z, iniSwellOffset
                            mov     StopOffset, par
                            add     StopOffset, #64 'points to beginning of current stop data
                            
                            rdlong  CurrentQueHeadCtr,QueHeadPtrAddr 'read location of current queue tail address
                            cogid   loopcounter 'REMOVE
                             call #testwrite    'REMOVE                  
    Initialize_ParseMidi_ret        ret
     fit
    DataByte3_z_MASK long %11111111_00000000_00000000
    'The following table converts byte 3 of a B0, 80/81 message to the appropriate stop byte to change
    tblStopMsg0 long $01_28_08_00 'HUB_StopStart + tblStopMsg, byte 0-4  current Stop byte in hub ram
    tblStopMsg1 long $29_19_31_11 'In a B0 message, byte 3 will = 0-84 which points to a byte index in this table
    tblStopMsg2 long $01_48_18_0A  'xxxx_xxdd dd points to the byte in these longs to use and the 6MSbits are
    tblStopMsg3 long $39_31_11_09   'the Long index from tblStopMsg0
    tblStopMsg4 long $29_21_19_41
    tblStopMsg5 long $1A_12_11_49
    tblStopMsg6 long $18_4A_2A_22
    tblStopMsg7 long $08_00_58_13
    tblStopMsg8 long $01_20_28_10
    tblStopMsg9 long $39_31_11_09
    tblStopMsg10 long $29_21_19_41
    tblStopMsg11 long $12_0A_02_49
    tblStopMsg12 long $14_2A_22_1A
    tblStopMsg13 long $50_15_13_0B
    tblStopMsg14 long $58_60_70_68
    tblStopMsg15 long $78_78_78_63
    tblStopMsg16 long $78_78_78_78
    tblStopMsg17 long $09_01_79_79
    tblStopMsg18 long $70_70_50_31
    tblStopMsg19 long $79_31_11_00
    tblStopMsg20 long $79_79_79_79
    tblStopMsg21 long $7B_7B_7B_7A
    tblStopMsg22 long $00_00_00_7B
    iniTransposerOffset     long 6272                     'Byte address Offset in Hub RAM
    iniSwellOffset          long 6273               
    QueBufferEndOffset      long 6688      
    QueBufferStartOffset    long 6292          
    QueHeadPtrAddrOffset    long 6284
    QueTailPtrAddrOffset    long 6288
    TransposeCmdMsg         long $B0_06                
    SwellCmdMsg             long $B0_07
    NoTranspose_z              long 64
    QueBufferEnd            res 1                   'Buffer End address after Hub offset applied
    QueBufferStart          res 1                   'Buffer Start address after Hub offset applied
    QueHeadPtrAddr          res 1                   'Loc in Hub Ram which stores the current Head address
    QueTailPtrAddr          res 1                   'Loc in Hub Ram which stores the current Tail address
    CurrentQueHeadCtr      res 1
    CurrentQueTailAddr      res 1
    QueReadData_Lng         res 1
    TransposerAddr_z        res 1
    SwellAddr_z             res 1
    StopOffset              res 1
    t1_z                      res 1
    tmp_z                   res 1
    RankPointer_z           res 1
    HUB_RAM_StartAddr_z     res 1
    StopHubBytePntr         res 1
    TransposerValue_z       res 1
    StopTablePtr        res 1
    StopTableValue          res 1
    BitPointer_z            res 1
    OutPinPointer_z         res 1
    ReadOffset_z            res 1
    tmpQue_Data_z             res 1
    StatusByte_z              res 1
    ReadAddr_z                res 1
    Byte1                   res 1
    Byte2                   res 1
    DataByte2_z                   res 1
    HUB_Cur_Stop_Addr_z       res 1
    BytePointer_z             res 1
    tmpStopByte             res 1
    tstAddr                 res 1'REMOVE
    LoopCounter             res 1
    
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-23 15:57
    I am at a complete loss right now and cannot explain what is going on. I will have to abandon this project as it is obvious my understanding of this device is insufficient to proceed.

    The full code (minus today's edits) is in the previous post.
    loopcounter is only used for the TestWrite routine

    In the code below, with the mov instruction remarked out I get the·bottom image (attached). When I leave this dummy mov instruction in I get the·top image (attached)

    What is supposed to happen is I capture from the Circular Queue, starting @ 1573 on the attached image "B0_07_xx" with xx being the variable in this message.

    In 1571 you "SHOULD" see a $0B which is written by the TestWrite routine.
    In 1568 you "SHOULD" see the variable from the B0_07_xx message in 1573 placed in the byte 1 position and byte 0 is left at its original value (it is)

    You will notice when I do NOT get the $0B in 1571 I do get the proper result in 1568 (makes no sense at all). I cannot explain where the $04 is generated.

    When I do not get the $0B I do get the byte written into 1568 as expected (again this makes not sense)

    I have moved the testwrite before and after the SUB tmp_z, #$0A and have yet to·see a "1" which should be the correct result as tmp_z = $0B.

    confused.gif
    ParseQueData
                            mov     DataByte2_z, QueReadData_Lng
                            and     DataByte2_z, #$FF     'strip off everything except data byte 2         
                            mov     StatusByte_z,QueReadData_Lng
                            shr     StatusByte_z, #16
                            mov     tmp_z, StatusByte_z
                            shr     tmp_z, #4       'removes Channel Nibble
     
    'BELOW IS THE DUMMY INSTRUCTION I EITHER LEAVE IN OR REMARK OUT
    'mov     loopcounter,tmp_z 'REMOVE TEST ONLY 
     
     
                            sub     tmp_z, #$0A' wc,wz'
     
    mov     loopcounter, tmp_z 'REMOVE TEST ONLY 
     call #testwrite 'This should write the value of tmp_z to 1571 (in my master array) 
     
                            add     tmp_z, #StatusJumpTbl
                            jmp     tmp_z  'jump to statusJumpTbl based upon value of StatusByte
    '===================================================================================                        
    StatusJumpTbl
                            jmp     #MainLoop_z''$Ax NOT USED Aftertouch
                            jmp     #ControllerCmd          '$Bx Controller
                            jmp     #ChannelMessage         '$Cx Program change
                            jmp     #mainLoop_z''$Dx NOT USED  Channel pressure
                            jmp     #mainLoop_z'NOT USED'$Ex Pitch wheel   Transposer values
                            jmp     #sysCommand_z             '$Fx System command
     
    .
    .
    .snip
     
     testwrite  'REMOVE TEST ONLY                        
                          wrlong    loopcounter,QueHeadPtrAddr'REMOVE TEST ONLY
                           nop
                           nop                    
     testwrite_ret          ret     'REMOVE TEST ONLY   
    
    
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-23 16:17
    One last test without attempting to add any dummy lines of code:

    Please note the different values I receive depending upon the placement of Call #TestWrite

    All I did was to cut and paste the mov and call to testwrite in 3 different places. In the code below I describe the values observed.

    ParseQueData
                            mov     DataByte2_z, QueReadData_Lng
                            and     DataByte2_z, #$FF     'strip off everything except data byte 2         
                            mov     StatusByte_z,QueReadData_Lng
                            shr     StatusByte_z, #16
                            mov     tmp_z, StatusByte_z
                            shr     tmp_z, #4       'removes Channel Nibble
     
    'STARTING RIGHT HERE tmp_z SHOULD = $0B
    
    mov     loopcounter, tmp_z 'test 1
     call #testwrite 'If placed here TestWrite never writes anything
     
                            sub     tmp_z, #$A'
     
    mov     loopcounter, tmp_z 'test 2
    call #testwrite 'If placed here TestWrite writes a $04 when it should be a $01
     
     
                            add     tmp_z, #StatusJumpTbl
     
    mov     loopcounter, tmp_z 'test 3
    call #testwrite 'If placed here TestWrite writes a $01
                            jmp     tmp_z  'jump to statusJumpTbl based upon value of StatusByte
    
    
    
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-23 17:24
    Last ditch effort.

    If I add the 2 NOPs shown, I can place the "mov wtf, tmp_z" anywhere in the lines of code shown and see the proper value in PropTerm and the rest of my code works. The jump to StatusJumpTbl works exactly as expected.

    I even loaded the latest IDE 1.06 since my last post with no change in results.

    I cannot base a project on something this flakey (assuming for just a moment it is not my code). The question was and remains, "why are 2 NOPs required after a SHR instruction"

    This is back to where I started this thread.

    ParseQueData
                            mov     DataByte2_z, QueReadData_Lng
                            and     DataByte2_z, #$FF     'strip off everything except data byte 2         
                            mov     StatusByte_z,QueReadData_Lng
                            shr     StatusByte_z, #16
                            mov     tmp_z, StatusByte_z
                            shr     tmp_z, #4       'removes Channel Nibble. for this test tmp_z = $0B at this point
     
    nop' if these 2 NOPs are added after the line above, the entire program works and the value of wtf is correct.
    nop 'if I move the NOPs before the "shr tmp_z, #4" I get a completely bogus value for tmp_z and wtf and the code does not work
             
                            sub     tmp_z, #$0A'
                            add     tmp_z, #StatusJumpTbl
    
    mov wtf, tmp_z 'REMOVE TEST ONLY
    call #testwrite 'Writes the value of wtf into master array 1571 REMOVE TEST ONLY
      
                            jmp     tmp_z  'jump to statusJumpTbl based upon value of StatusByte
    
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-23 18:00
    Wulitzer,
    I thought of your issue yesterday, when I wrote "...one unsolved due to the missung FULL code ..." smile.gif
    But you posted your full code don't you? No!

    See, as soon as the COG is loaded with your code nothing can harm it any longer.... but before, it can!

    I - and most likely others as well - have thoroughly looked through it. It was obvious from the beginning that this all had nothingti do with timing or so
    (And no, there are no "two schools of thinking" smile.gif only one!)

    The first idea - before you posted this greater part of your program - was some misfit of RES, maybe a preset variable behing a RES,
    which can happen very easily. However this was not the case, your total amount of machine code was rather low, and that left me with only
    one solution: Your main program overwrites some of the assembly code before it is copied to the COG!

    I am especially unhappy with these lines from your code here:
    iniTransposerOffset     long 6272                     'Byte address Offset in Hub RAM
    iniSwellOffset          long 6273              
    QueBufferEndOffset      long 6688     
    QueBufferStartOffset    long 6292         
    QueHeadPtrAddrOffset    long 6284
    QueTailPtrAddrOffset    long 6288
    


    Such things scvhould not exist at all... They are bound to give you trouble, if not immediately then later...

    Sorry I can't help more.... An idea to check this:
    Just before the ORG 0 of your COG code, add a LONG 0[noparse][[/noparse]300]. If the smptoms disappear, then we are on the right track!

    Post Edited (deSilva) : 2/23/2008 6:06:18 PM GMT
  • hippyhippy Posts: 1,981
    edited 2008-02-24 14:32
    Wurlitzer said...
    I cannot base a project on something this flakey (assuming for just a moment it is
    not my code).

    I think reality is that it is your code, even if not the code where the problem appears to be. I've seen
    no inherent flakiness in the Propeller although I'm quite sure all of us have been convinced that our
    problems must be down to hardware faults and not our software at some time.

    Adding the NOP's doesn't identify the underlying problem nor resolve it, but simply masks it. I think
    you are too focused on that fix and not on the bigger picture which is where the problem originates.

    There's nothing fundamentally wrong with the PASM code which adding NOP would fix as best anyone
    who has looked at the code can tell ( deSilva has a good point about hard-wired constants ), so the
    obvious conclusion to me is that the underlying problem must be elsewhere.

    The only suggestions I have are to use some debugging within the code ( difficult if moving things
    around alters how it works ) or take a deep breath, stop digging one hole and move on to digging
    another. Rip up all you've done and implement again using what you've learned along the way. A
    rewrite is often not the painful experience it may look to be and can often be implemented quite
    quickly and the result is often better for it.

    As frustrating as it is, you won't be the first person up a blind-alley who has 'ballsed-up their code'
    with no idea as to how or where they've done that. It's all part of the programmer's territory as is
    knowing when to stop banging ones head against the wall and to move to a different approach or to
    start again. Been there, done that, I have a whole drawer full of T-shirts.
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-24 15:14
    Thanks to all who have put up with this thread. deSilva/Hippy yes you are both right. jumpin.gif

    While I did post all of the offending COG code·I did·not post the entire Spin object which contained 2 Dat statements hence 2 separate assembly program segments.

    I thought I was saving everyone's time in not sending code that was 100% operational and "SHOULD" not have been related to the problem. I value your time as much as my own. In fact, I wasted your time. Sorry!

    This morning I remarked out the entire offending code and created a separate spin file and place the code there with the associated spin code to launch the assembly portion and with one notable exception it compiled properly and ran fine. No added NOPs required.

    In the StatusJumpTbl there was a JMP #ChannelMessage which was a section of code not yet developed and only had a JMP #MainLoop_z so I never expected any problem there.

    However, the actual label was :ChannelMessage but when this code was in its original place with the other assembly program the compiler never complained about the mismatch as in the other assembly program there was a label "ChannelMessage".

    As my problem code "SHOULD" have never jumped to ChannelMessage under these testing conditions I did not pay attention to the label conflict.

    One last request guys! I would rather not face this issue again so I want to keep the assembly programs as completely separate as possible.

    I have 1 spin program and 6 assembly routines. What is the safest way to launch all of these without tying up cogs with "helper" spin objects to launch all the assembly programs?







    ·
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-24 15:21
    Wurlitzer said...
    However, the actual label was :ChannelMessage but when this code was in its original place with the other assembly program the compiler never complained about the mismatch as in the other assembly program there was a label "ChannelMessage".
    DeSilva is an idiot is an idiot!!
    Of course I loaded your code into the PropellerTool and it complained!
    I silently fixed that!
    I thought: " some experimenting of Wulitzer... Never expected he send me anything functional anyhow..."

    Would not have been this idiotic quarrel with Mosquite the other day, you should have received
    a sharp remark from me, and we would have solved this puzzle already the day before yesterday smile.gif

    Post Edited (deSilva) : 2/24/2008 3:26:23 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2008-02-24 16:15
    Wurlitzer,
    The normal way to initiate an assembly program in a cog while packaging up the assembly program in a object is to have a single Spin start routine in that object that simply does a COGNEW and returns a zero (false) if there are no free cogs or the number of the cog + 1 if a cog is started. This takes only a few bytes:
    PUB start(parValue)
       result := cognew(@entry,parValue) + 1
    DAT
    entry
    
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-24 16:46
    Edit: Deleted
    Sorry, my little idea here does not work!!

    Post Edited (deSilva) : 2/24/2008 5:02:59 PM GMT
  • hippyhippy Posts: 1,981
    edited 2008-02-24 16:52
    I agree with Mike, simply package the PASM in a sub-object, call its Start/Main and launch the PASM. It can be a bit of a pain for some PASM which is less than self-contained - references stuff which is outside itself in RAM - but safer all round to put everything in a single object or code the PASM to build up its pointers to the data it will be using.

    Jumping from on Cog into another Cog ... yes, somewhere round here I have that T-Shirt smile.gif

    Glad you got it sorted.
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-24 17:09
    o.k. so once again..
    Segregation is not free of charge...

    In contrast to what Mike implied (sorry Mike, I know you did not say it!) is that a PASM COG need not be initiated from the same object!
    That is just a constraint for SPIN-COGs due to heavy internal workings (we now understand better than before).

    Whenever you've got an address, you can "cog" it!

    Hoewever you cannot easily get an address out of an Object smile.gif It always needs a routine.

    So the alternative to Mike's "standard procedure" is:
    in main:
      theAsmAddr:= module.getCodeAddress
      COGNEW(theAsmAddr, thePar)
    
    
    and in the "module":
    
    SUB getCodeAddress:addr
       addr := @asm
    DAT
       ORG 0
    asm
    



    No real advantage in fact, but maybe interesting in some other context!
    Note that the compiler distinguishes the both kinds of COGNEW by whether it gets a routine or a variable as first argument..
    So COGNEW(modul.getAsmAddr,..)
    is no good at all smile.gif

    Post Edited (deSilva) : 2/24/2008 5:21:49 PM GMT
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-24 17:42
    Mike, what I have done now is to place every assembly routine in its own SPIN file with a start and stop object. My top object then one by one calls the various spin objects lets them load their respective assembly routines then calls the spin stop object to kill that instance of spin. I do that in the top object until every assembly routine is running and I believe all the other Spin routines have stopped and released their cogs.

    The reason I was attempting to place 2 assembly routines in a single spin file was I thought I might get to the point where I had 7 cogs running and launching another assembly program using another spin object would not be possible.

    I know now that while 2 assembly routines can reside in a single spin file I have to be 100% positive there are no duplicate labels. The compiler does not catch my stupid mistakes with labels.

    Thanks again for you input.
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-24 17:48
    Wurlitzer said...
    My top object then one by one calls the various spin objects lets them load their respective assembly routines
    then calls the spin stop object to kill that instance of spin. I do that in the top object until every

    No, there is no INSTANCE OF SPIN. this all works by one and the same SPIN interpreter in your main COG.
    STOP will stop the assembly routines you so carefully have set up a moment ago smile.gif
    You most likely need no stop at all in the first place
  • WurlitzerWurlitzer Posts: 237
    edited 2008-02-25 17:31
    deSilva wrote: "No, there is no INSTANCE OF SPIN. this all works by one and the same SPIN interpreter in your main COG.
    STOP will stop the assembly routines you so carefully have set up a moment ago smile.gif
    You most likely need no stop at all in the first place
    "

    What I did, to completely eliminate the possibility of dup labels or variable names was from the top object:

    Public Main

    'then launch· spin file object MidiIn.
    MidiIn.Start(26, @MasterArray) 'this object file contains minimal spin just to launch assembly program #1

    'wait·enough time to allow this spin file to launch the assembly program·then stop the MidiIn spin object.
    MidiIn.stop 'this only stops the spin portion the assembly continues to run. I made sure I stopped the right cog

    'then launch a·2nd spin file object.
    MidiParse.Start(26,@MasterArray) 'this object file contains minimal spin just to launch assembly program #2

    'wait·enough time to allow this spin file to launch the assembly program·then stop the MidiIn spin object.
    MidiParse.Stop 'again making sure the "cog stop", stopped the proper cog.

    etc, etc until all the required cogs (minus 1) are merrily running their respective assembly routines.

    Then finally 'launch the· assembly routine in the top object file
    This seems to work well.

    This may not be the best way to do this, but after the last week I wanted to make sure I did not duplicate the same problem.
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-25 17:48
    Wurlitzer, what you describe sounds confusing, is not what one does "normally" and seems unneccessarily complicated!

    But reading it again... No, I do not understand it...
    How do your "STOP" routines look like???.

    Post Edited (deSilva) : 2/25/2008 5:54:43 PM GMT
Sign In or Register to comment.