At the tail end of my bubble project, I was left with one messy spot of code, that being the 'Wait' macro. 'Wait' is used to waste a certain ammount of instructions to allow real world events to occure. In fact, most of the frame time is spent nop-ing instead of processing info. Attempt one was simple and direct:
Well, it works, but it takes another ROM location per wasted cycle. That's a double waste. Sure, I had plenty of room to waste (my choice of processor can store a K of instructions, which is really way planty), but this lacks a certain elegance. So.... Wait2 uses loops to waste time. Timing a loop on a PIC is a bit tricky, as all instructions execute in 1 cycle EXCEPT for any branch taken, which is 2 cycles. Furthermore, the only machine lever branch testing conditionals (ie, jmp IF) are of the form "If X true, skip next instruction" Case in point, the conditional I use here is called 'decfsc' for dec f (register) and skip next instruction if f is now zero. One never truly gets used to instuctions like this. I usually end up alising them into more human compatable terms. One point to keep in mind here, there is no RAM in the conventional sense, just a bunch of 8 bit registers. The W register is special, it's the working register, sort of an accumulator; W is also 8 bits long. OK, so here's the revised macro:
Wait MACRO cycles LoopCount = cycles while LoopCount > 0 nop LoopCount -- endw ENDM
Lot's more compiler thought here, but much simpler (and lower code count) while executing. Let's take the trivial case where cycles =3 For 3, the whole "LongLoop" piece is skipped. Instead, the macro resolves to:
Wait2 MACRO cycles LOCAL Remainder, LongLoops, jf1, jf2 IF cycles >= 4 ; we can make a loop to handle these LongLoops SET (cycles - 1 ) / 3 Remainder SET cycles - ( LongLoops * 3 ) - 1 movlw LongLoops movwf WaitCount LongLoop: decfsz WaitCount, F goto LongLoop ELSE Remainder SET cycles ENDIF IF Remainder == 3 goto jf1 jf1: nop ENDIF IF Remainder == 2 goto jf2 jf2: ENDIF IF Remainder == 1 nop ENDIF ENDM
Not bad, 3 cycles for 2 instructions. (THREE cycles? Sure, the goto takes 2 cycles itself, plus one for the nop). The only time this gets used is when exactly 3 cycles are to be wasted. For 1 or 2, the other macros take over. For more then 3, the LongLoop wastes most of the time, and just one or two cycles are wasted at the tail. The big waste of time occures in this part of LongLoop:
goto jf1 jf1: nop
We only get here for 4 or more cycles. For LongLoops = 1, the loop terminates without looping (remember, skip IF zero, so the goto LongLoop isn't executed). So the shortest loop is 4 cycles. Each LongLoop we do goto expends 3 cycles (1 for the decfsz, two for the goto). How much can it waste? Well, we can fill LongLoops with zero to get 256 loops for a total waste of time of 769 cycles. It would be nice to raise an error is more then this is requested, but due to some compiler feature (bug) I can't get the IF to work. So at it's longest when wasting (5 + 3N), or (6 + 3N) cycles, the routine takes 5 instuctions. For (4+3N), it takes just 4 instructions. That's pretty tight code for a complete waste of time.
LongLoops SET (cycles - 1 ) / 3 Remainder SET cycles - ( LongLoops * 3 ) - 1 movlw LongLoops movwf WaitCount LongLoop: decfsz WaitCount, F goto LongLoop ELSE
Sorry ernie, But the people I work with have wasting time down to a sience, they can do it better then any program you can comeup with. You see, people on an hourly wage, have to learn to waste time. it just life.... someday we may beable to teach computers to waste time like humans, the only people I know that are very close to this is Microsoft.... Zcoder.....