MMcLaren wrote:It seems your WAIT preprocessor language macro lacks the capability I described. ... though I understand now that you have other macros that will fulfill the requirement.
Exactly. I wrote that macro to illustrate a different point. However, modifying it to take a optional argument that is the number of cycles to wait less then the specified time is trivial:
- Code: Select all
////////////////////////////////////////////////////////////////////////////////
//
// Macro WAIT sec [, cycles]
//
// Wait the indicated time from the previous instruction until the next
// instruction is executed. SEC is amount of time to wait in seconds. The
// preprocessor constant FREQ_INST must be previously defined to indicate the
// instruction clock frequency.
//
// The optional CYCLES argument is the number of instruction cycles less to
// wait than the time specified by SEC. CYCLES defaults to 1.
//
// The actual wait will be rounded to the nearest number of whole instruction
// cycles.
//
// The variable WAITCNT is trashed.
//
/var new labeln integer = 0 ;for making unique number per macro invocation
/macro wait
/var local sec real = [arg 1] ;desired wait time in seconds
/var local nwcy integer = 1 ;number of cycles not to wait
/if [exist 2 arg] then
/set nwcy [arg 2]
/endif
/var local nwait integer ;number of cycles left to wait
/var local ii integer ;scratch integer
/var local r real ;scratch floating point
/set labeln [+ labeln 1] ;make unique 1-N number of this macro invocation
/set nwait [rnd [* sec freq_inst]] ;make cycles specified by SEC
/set nwait [- nwait nwcy] ;minus the cycles to explicitly not wait
/if [<= nwait 0] then ;no cycles to wait ?
/quitmac
/endif
/set r [/ nwait freq_inst] ;actual additional wait time, seconds
/write
/write " ; Wait " [eng r] "s (" nwait " cycles)"
/write " ;"
//
// Do long waits by spinning in a loop. This loop waits 3 cycles for each
// iteration plus 4 overhead cycles.
//
/if [>= nwait 7] then ;at least one iteration to wait ?
/set nwait [- nwait 4] ;account for loop entry/exit overhead cycles
/set ii [div nwait 3] ;determine number of loop iterations
/set nwait [- nwait [* ii 3]] ;update cycles left to wait
/if [> ii 255] then ;too many iterations for this algorithm ?
/show " Wait time of " [eng sec] "s is too long for the WAIT macro"
error Wait
end
/stop
/endif
movlw [and [+ ii 1] 16#FF]
movwf waitcnt
waitloop[v labeln]
decfsz waitcnt
goto waitloop[v labeln]
/endif
//
// Wait two cycles at a time by using GOTO $+1
//
/block
/if [< nwait 2] then ;not enough cycles left for this method ?
/quit
/endif
goto $+1
/set nwait [- nwait 2]
/repeat
/endblock
//
// Wait the remaining cycles by explicit NOPs.
//
/block
/if [<= nwait 0] then ;no cycles left to wait ?
/quit
/endif
nop
/set nwait [- nwait 1]
/repeat
/endblock
/endmac
This time I didn't test it, didn't even try to build it, so can't say for sure it is correct. Note the new optional second parameter. That defaults to 1 cycle, so previous code using this macro without the second parameter should work identically.
May I impose once more to ask about your ASPIC preprocessor language, please? It seems you have a lot more capability in the format of parameters compared to standard MPASM macros. How is that possible? Is the ASPIC preprocessor an application of some sort?
The MAPASM and ASM30 preprocessor is a executable called PREPIC. In my build environment, I write .ASPIC (and .DSPIC on 16 bit core parts) source files. These are translated by the preprocessor to produce the .ASM file for MPASM or the .AS file for ASM30, which are then translated with the Microchip assemblers as usual.
While I'm sure your ASPIC preprocessor macro language is very useful and a very productive tool for you, the language and syntax seems quite alien to me.
Any new language is going to seem strange. Like all such things, it's no longer strange once you learn it.
The PREPIC syntax was dictated in part by having to live around the MPASM and ASM30 syntax. This was done by having preprocessor commands start with a slash, and inline functions be enclosed in brackets. Once you realize that the inline functions use a operator-first notation, things aren't really all that hard to understand. For example, old HP calculators were famous for using "reverse polish", which is operator-last. To add 5 and 7 you'd say "5 7 +". With PREPIC you say "+ 5 7", which makes parsing simple and the whole structure highly regular.
For the details see
http://www.embedinc.com/pic/prepic.txt.htmIt doesn't seem any more intuitive to me now than it did when I looked at it ten years ago. For example, it's not obvious (to me) how your WAIT macro is any better or worse than a similar standard MPASM macro (example below, 14-bit core), except that I can actually understand the MPASM macro (grin).
The MPASM macro facility is rather primitive. It can do some things, but other things are either difficult, awkward, or impossible. Your MPASM example wait macro does a lot less than my PREPIC macro, so it's apples versus oranges. Yours doesn't take a time value and compute the number of cycles, does no error checking for the wait time being too long (it will just silently produce the wrong delay), and couldn't emit a nice readable error message if it did. Surprisingly, after all your complaining about wanting a fixed time wait minus some cycles, yours doesn't do that either.
PREPIC features that my macro makes use of that MPASM can't do include floating point arithmetic and optional arguments. MPASM macros are also rather bad at string manipulation, there are problems with LOCAL, etc. Now I mostly just write PREPIC macros, whether they could have been written easily in native assembler or not.