Shop OBEX P1 Docs P2 Docs Learn Events
Embedded REPT's Crash/Error HELP!! — Parallax Forums

Embedded REPT's Crash/Error HELP!!

LewisLewis Posts: 23
edited 2006-12-08 18:00 in General Discussion
Hello,

I'm using the latest version of the SX-Key IDE and SASM crashes when I do the following:

rept 5
    rept 3
    jmp $+1
    endr
    
    rept 3
    nop
    endr
endr




If I were to remove the rept 5 encasing the inner two rept's, it will assemble with no problem. But here's another weird scenario:
REPT 5
    mov    rc, #CBURST_HIGH
    rept 3
    nop
    endr
ENDR




This has an embedded rept and it assmebles without an issue but once I embedded another one in there, it crashes. My problem is that I'm working with a Delay MACRO written for the XGS and it seems to crash on me when the logic embeds 2 or more rept's inside another rept block.

Here's the Delay MACRO:

DELAY MACRO clocks
; the preprocessor can NOT do floating point math, so another construction would be to scale
; all values by 10 then multiply by 8 rather than 80, for example, a 4.5 uS delay could be
; written
; DELAY(8*45)

; first compute fractional remainder of 10 and delay
IF (((clocks) // 10) > 0)

  ; first 3 clock chunks
  REPT (((clocks) // 10)/3)
    JMP $ + 1
  ENDR

      ; now the remainder if any
  REPT (((clocks) // 10)//3)
    NOP
  ENDR

ENDIF

  ; next multiples of 100
  IF (((clocks) / 100) >= 1)
    ; truncated for brevity
  ENDIF

  ; last compute whole multiples of 10, and delay
  IF (( ((clocks) // 100) / 10) >= 1)
    ; truncated for brevity
  ENDIF

ENDM




And the code that I'm trying to write is this:

REPT 5
mov RC, #CBURST_HIGH    ; ( 2 cycles ) 
Delay(11-2) 

mov RC, #CBURST_LOW    ; ( 2 cycles ) 
Delay(11-2)
ENDR




If you follow the logic of the MACRO, you will find that 9 or (11-2) causes the assembler to create two rept blocks in place of this Delay instruction--which happens to be within the outter REPT 5 block.

Please point me in the right direction smile.gif This is driving me nuts. I hope there's a workaround or a bugfix patch somewhere.

Thanks,

- Lewis [noparse][[/noparse]m80] -

Comments

  • PJMontyPJMonty Posts: 983
    edited 2006-11-27 16:46
    Lewis,

    I haven't had a chance to look into the SASM code to see what is going on. However, my first assumption is that the "rept" command was never designed to be nested. The example that works may be getting by on a fluke. The other possibility is that "rept" is designed to be nested, but that there is a bug in SASM that causes it to fail. Either way, it will take a bit of time digging into SASM to come up with an answer. Send me a PM in a few days if I haven't replied to this thread with some sort of update/answer.
      Thanks, PeterM
  • LewisLewis Posts: 23
    edited 2006-11-27 17:26
    Thanks Peter! I appreciate you taking a look at this. Are you the author of SASM?

    - Lewie [noparse][[/noparse]m80] -
  • PJMontyPJMonty Posts: 983
    edited 2006-11-27 19:33
    Lewis,

    I maintain and upgrade both SASM and the SX_Key IDE for Parallax. I'm a freelance programmer, so I don't work for Parallax directly.

    Thanks,
    PeterM
  • PJMontyPJMonty Posts: 983
    edited 2006-11-28 00:52
    Lewis,

    Tiny update - Yes, SASM allows nested REPTs. The problem now is to figure out why actually taking advantage of that feature causes a crash.
      Thanks, PeterM
  • LewisLewis Posts: 23
    edited 2006-11-28 01:43
    Hey, maybe this might help--

    When calling two Delay macros that evaluate to only 1 rept block each would look like this:
    REPT 5
    mov RC, #CBURST_HIGH    ; ( 2 cycles ) 
    Delay(4) 
    
    mov RC, #CBURST_LOW    ; ( 2 cycles ) 
    Delay(4)
    ENDR
    
    



    Doesn't seem to crash for two reasons (even though two rept blocks are being nested within rept 5.
    a) When Delay is 4, the macro seems to put only 1 rept block in it's place... Remember that a single nested block compiles fine.
    b) Also notice that there are two Delays here but it compiles just fine because I think SASM first unravels the first Delay into "pure code" before evaluating the next macro.

    Might look like this after one block is evaluated:
    REPT 5
    mov RC, #CBURST_HIGH    ; ( 2 cycles ) 
    NOP
    NOP
    NOP
    NOP 
    
    mov RC, #CBURST_LOW    ; ( 2 cycles ) 
    Delay(4)
    ENDR
    
    



    Which is fine... because the next Delay is going to place only 1 more rept block as well before it unravels it.

    In my opinion, it seems SASM is having problem evaluating 1 block before the other--or it doesn't know how to prioritize them... might be a recursive issue. But let's hope not!

    Anyway, hope that helps! Also, let me know if you need me to find more cases.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - Lewis [noparse][[/noparse]m80] -
  • PJMontyPJMonty Posts: 983
    edited 2006-11-28 02:45
    Lewis,

    Hmm, getting ugly here in SASM-land. The problem appears to be that whomever originally wrote SASM (or performed later updates) allowed nested REPT commands, but never took into account the possibility that inside a nested REPT there might be two or more sequential REPTs.

    In other words, they assumed this:

    REPT 5
        REPT 2
            REPT 4
            ENDR ; close the rept 4
        ENDR ; close the rept 2
    ENDR ; close the rept 5
    



    ...and never saw this coming:

    REPT 5
        REPT 2
        ENDR ; close the rept 2
        REPT 4
        ENDR ; close the rept 4
    ENDR ; close the rept 5
    



    In the second example, what ends up happening is that when SASM sees the closure for "REPT 2", it basically drops down a nesting level, since it assumes that not encountering another REPT means the code has no more nesting in it. When it then hits the "REPT 4", it dutifully starts expanding the desired number of repeats. This works great for the first pass of "REPT 4", but when it starts the next pass, it incorrectly starts using the code and number of repetitions for "REPT 2". It then continues to repeat the "REPT 2", and when that is done it finds the "REPT 4" again, and the process repeats.

    Here was your code:

    rept 2 ; Outermost rept
        rept 3 ; 1st inner rept
        jmp $+1
        endr  ; 1st inner rept closure
        
           rept 3 ; 2nd inner rept
        nop
        endr ; 2nd inner rept closure
    endr ; Outermost rept closure
    



    SASM (incorrectly) expands this into:

    jmp$ + 1
    jmp$ + 1
    jmp$ + 1
    nop
    jmp$ + 1
    jmp$ + 1
    nop
    jmp$ + 1
    jmp$ + 1
    nop
    etc, etc, etc...
    
    



    I am not 100% sure yet, but this may require an architectural change to SASM rather than a bug fix. I have to give this some more thought for what the fix would entail (time = money) and then contact Parallax to see about whether this gets officially scheduled for fixing. Sorry for the not so upbeat news...
      Thanks, PeterM
  • LewisLewis Posts: 23
    edited 2006-11-28 03:03
    Thank you once again for the updates! I hope Parallax approves this change--there are hundreds of people using this macro and assembler. It might be a headache for you, but like you said, time = $ [noparse]:)[/noparse]

    Is there a way to make it expand inner repts untouched until the outter rept is decoded?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - Lewis [noparse][[/noparse]m80] -
  • PJMontyPJMonty Posts: 983
    edited 2006-11-28 04:17
    Lewis,

    There is where it becomes more of an architectural change than a bug fix. Assemblers by their nature are linear beasts. They go through the code line by line in the sequence it was written. Without first finding all REPT blocks, there is no easy way to know you are working on the "inner" REPTs versus the outer REPT. In addition, you're assuming a solution that handles your particular example without also assuming that there will someone else doing something even more "interesting" with the assembler. For example, it's conceivable that someone might write code like this:

    REPT 2
        REPT 3
        ENDR ; 3
    
        REPT 4
            REPT 5
            ENDR ; 5
    
            REPT 6
            ENDR ; 6
        ENDR ; 4
    ENDR ; 2
    
    



    Now there is an "inner-inner" block to handle as well as the previously mentioned "inner" block. Furthermore, all of this is complicated by the presence of the IF assembler conditional and the possibility that inside REPT blocks may contain macros which themselve may contain nested or sequential (or both) REPT blocks. It all gets nasty quickly, and it makes it impossible to test the assembler against all possible legal code sequences.
      Thanks, PeterM
  • LewisLewis Posts: 23
    edited 2006-11-28 12:52
    Nasty, ugly, disgusting, and who would've thought that parsing directives are more cryptic than translating mnemonic to machine code!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - Lewis [noparse][[/noparse]m80] -
  • LewisLewis Posts: 23
    edited 2006-11-30 18:29
    Hey Peter,

    Any luck?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - Lewis [noparse][[/noparse]m80] -
  • PJMontyPJMonty Posts: 983
    edited 2006-12-01 16:30
    Lewis,

    Not really. I thought I had a (relatively) simple solution that wouldn't require a lot of code "rip up and re-do", but it didn't work out. Still working on it...
      Thanks, PeterM
  • LewisLewis Posts: 23
    edited 2006-12-08 18:00
    Peter,

    Has the SASM driven you mad yet? I know it must be a pain to maintain an assembler like this. How's it going?

    -Lewis

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - Lewis [noparse][[/noparse]m80] -
Sign In or Register to comment.