Embedded REPT's Crash/Error HELP!!
Lewis
Posts: 23
Hello,
I'm using the latest version of the SX-Key IDE and SASM crashes when I do the following:
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:
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:
And the code that I'm trying to write is this:
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 This is driving me nuts. I hope there's a workaround or a bugfix patch somewhere.
Thanks,
- Lewis [noparse][[/noparse]m80] -
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 This is driving me nuts. I hope there's a workaround or a bugfix patch somewhere.
Thanks,
- Lewis [noparse][[/noparse]m80] -
Comments
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
- Lewie [noparse][[/noparse]m80] -
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
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
When calling two Delay macros that evaluate to only 1 rept block each would look like this:
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:
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] -
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:
...and never saw this coming:
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:
SASM (incorrectly) expands this into:
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
Is there a way to make it expand inner repts untouched until the outter rept is decoded?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- Lewis [noparse][[/noparse]m80] -
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:
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
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- Lewis [noparse][[/noparse]m80] -
Any luck?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- Lewis [noparse][[/noparse]m80] -
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
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] -