Here are the three other non-trivial code blocks requiring STALLI/ALLOWI to REP changes:
' Write bitfield (12 longs, must be in regs)
'
wrf mov fd,x 'get bitfield data
rol fd,fb
bmask fm,sz 'make bitfield mask
rol fm,fb
mov fx,x 'preserve x
stalli 'protect variable
wrf_rd push #$1FF 'read variable into x (rewritten) (initially: push $1FF, to begin xbyte on _ret_)
setq fm 'set bitfield mask (initially: no consequence)
muxq x,fd 'mux bitfield data into x (initially: no consequence)
wrf_wr _ret_ setq #$0A1 'write x back to variable (rewritten) (initially: begin xbyte, compress Ax..Fx, write flags)
allowi 'unprotect variable
_ret_ mov x,fx 'restore x
' Variable assignments / math operators (85 longs)
'
una_iso mov w,x ' m a: !!
una_psh pusha x 'push | n b: !
alti rd 'rd m n c: - (neg)
op_notb test x wz 'rd,!! m n a d: ABS
op_quna stalli ' x x | i j k e: ENCOD
qsqrt x,#0 'SQRT x x | i | | f: DECOD
qlog x 'LOG x x | | j | g: BMASK
qexp x 'EXP x x | | | k h: ONES
muxz x,_FFFFFFFF '!! x x a | | | i: SQRT
op_not not x '! x x | b | | | j: LOG
op_neg neg x '- x x | | c | | | k: EXP
op_abs abs x 'ABS x x | | | d | | |
op_encod encod x 'ENCOD x x | | | | e | | |
op_decod decod x 'DECOD x x | | | | | f | | |
op_bmask bmask x 'BMASK x x | | | | | | g | | |
op_ones ones x 'ONES x x | | | | | | | h | | |
getqx x ' x x | | | | | | | | i j k
allowi ' x x | | | | | | | | i j k
alti wr 'wr m n | | | | | | | | | | |
ret 'wr,op m n a b c d e f g h i j k m: ?= var (isolated)
_ret_ mov x,w 'iso m | n: ?= var (push)
_ret_ zerox x,sz 'push n x: use a..j
mul_mod abs w,x wc 'C=ys x x b d g a: *
muu_mod mov w,x ' x x a | c | e f | h b: /
alti rd 'rd m n | | | | | | | | c: +/
popa x 'rd,op m n a b c d e f g h d: //
testb x,#31 wz 'Z=xs x x | b | d | | g | e: +//
abs x ' x x | b | d | | g | f: SCA
stalli ' x x a b c d e f g h g: SCAS
qmul x,w '*,SCAx x x a | | | | f g | h: FRAC
qdiv x,w '/,// x x | b c d e | | |
qfrac x,w 'FRAC x x | | | | | | | h
getqx x ' x x a b c | | | | h
if_c_ne_z neg x '*,/ x x | b | | | | | |
getqy x ' x x | | | d e f g |
if_z neg x '// x x | | | d | | | |
call #\.scas 'SCAS x x | | | | | | g |
allowi ' x x a b c d e f g h
alti wr 'wr m n | | | | | | | |
ret 'wr,op m n a b c d e f g h m: var ?= exp (isolated)
_ret_ popa x 'iso m | n: var ?= exp (push)
_ret_ zerox x,sz 'push n x: use a..h
For the _RET_ to take effect, it appears that the repeat instruction count has to be one more than the number of instructions executed in the REP block.
As per the examples of using REP, the ".end" label is meant to be placed after the last instruction of the REP block.
That 3rd case that TonyB_ posted above with the extra "neg x" (b,d paths) looks tricky to solve with a REP as the instruction counts will differ. It would need rearrangement somehow to bring the counts to the same length.
Depending on what the m,n,x cases need to do you might be able to move this line to follow the GETQY after which you could have interrupts enabled. That could possibly get the REP counts the same for the CORDIC part.
No, in these cases REP isn't intended for looping. The specified REP length just has to be longer is all. May as well be REP #511, #1. The final RET branch cancels the REP mechanism, restoring IRQ handling.
Yeah ok, that's right, it's not looping and that ret branch there should save us when it cancels the REP. In general this REP+SKIPF stuff does need careful thought as to where it works and it can be tricky. I know I've been caught there before in my video driver work.
A label is safe. What I was concerned about was acceptable norm of using an exact number for looping. Or in this case, trying to be exact even though it isn't looping.
Thanks for all these REP ideas. I was able to get rid of all ALLOWI instructions by substituting REP for STALLI. This saved 14 instructions in the interpreter, which is pretty significant. It freed up 4 longs in cog register space and 10 longs in hub space.
Here is the most complicated usage or REP to shield CORDIC operations from interrupts. I used #99 just to cover every case and imply infinity. The interrupt protection ends when the call/ret/_ret_ execute, which is fine:
mul_mod abs w,x wc 'C=ys x x b d g a: *
muu_mod mov w,x ' x x a | c | e f | h b: /
alti rd 'rd m n | | | | | | | | c: +/
popa x 'rd,op m n a b c d e f g h d: //
testb x,#31 wz 'Z=xs x x | b | d | | g | e: +//
abs x ' x x | b | d | | g | f: SCA
rep #99,#1 ' x x a b c d e f g h g: SCAS use REP to protect cordic operation until call/ret/_ret_
qmul x,w '*,SCAx x x a | | | | f g | h: FRAC
qdiv x,w '/,// x x | b c d e | | |
qfrac x,w 'FRAC x x | | | | | | | h
getqx x ' x x a b c | | | | h
if_c_ne_z neg x '*,/ x x | b | | | | | |
getqy x ' x x | | | d e f g |
if_z neg x '// x x | | | d | | | |
getqx w 'SCAS x x | | | | | | g |
call #\.scas 'SCAS x x | | | | | | g |
alti wr 'wr m n | | | | | | | |
ret 'wr,op m n a b c d e f g h m: var ?= exp (isolated)
_ret_ popa x 'iso m | n: var ?= exp (push)
_ret_ zerox x,sz 'push n x: use a..h
.scas if_c_eq_z jmp #.scas2 'adjust 64-bit product for SCAS
neg w wz 'conditionally negate {x,w}
if_nz not x
if_z neg x
.scas2 shl x,#2 'x = {x,w}[61:30]
shr w,#32-2
_ret_ or x,w
I posted a new v35a, in which the interpreter has been shrunk by 14 longs by using REP as an interrupt shield, instead of STALLI+ALLOWI.
There's a very slight performance increase, but I'm mainly wanting to put it out now, in case anyone notices a problem with it. Seems to work fine for me. I'm extremely careful when I make these kinds of edits, because things can go sideways in unexpected ways. Just interested to see if anybody has a problem with it.
I posted a new v35a, in which the interpreter has been shrunk by 14 longs by using REP as an interrupt shield, instead of STALLI+ALLOWI.
There's a very slight performance increase, but I'm mainly wanting to put it out now, in case anyone notices a problem with it. Seems to work fine for me. I'm extremely careful when I make these kinds of edits, because things can go sideways in unexpected ways. Just interested to see if anybody has a problem with it.
So what are you going to squeeze into this new found space
I posted a new v35a, in which the interpreter has been shrunk by 14 longs by using REP as an interrupt shield, instead of STALLI+ALLOWI.
There's a very slight performance increase, but I'm mainly wanting to put it out now, in case anyone notices a problem with it. Seems to work fine for me. I'm extremely careful when I make these kinds of edits, because things can go sideways in unexpected ways. Just interested to see if anybody has a problem with it.
So what are you going to squeeze into this new found space
Nothing, at this point. Just good to conserve where you can, because we'll need it in the future.
"_ret_ altd" would affect the next instruction in the pipeline, but that next instruction would get cancelled due to the _ret_.
We could do "_ret_ neg x", for those unary cases which don't write back to the variable, but it would take an extra instruction for each case. By using a discrete ret after, we can get all three use cases out of "neg x".
Comments
Depending on what the m,n,x cases need to do you might be able to move this line to follow the GETQY after which you could have interrupts enabled. That could possibly get the REP counts the same for the CORDIC part.
Here is the most complicated usage or REP to shield CORDIC operations from interrupts. I used #99 just to cover every case and imply infinity. The interrupt protection ends when the call/ret/_ret_ execute, which is fine:
Here is the new interpreter with these changes.
This trick needs to go into the P2 Tricks and Traps Reference thread.
There's a very slight performance increase, but I'm mainly wanting to put it out now, in case anyone notices a problem with it. Seems to work fine for me. I'm extremely careful when I make these kinds of edits, because things can go sideways in unexpected ways. Just interested to see if anybody has a problem with it.
Nothing, at this point. Just good to conserve where you can, because we'll need it in the future.
ALTI D is an interesting instruction. Just wondering whether a _RET_ prefix will do a RET after D replaces next instruction.
EDIT:
Duff code deleted
We could do "_ret_ neg x", for those unary cases which don't write back to the variable, but it would take an extra instruction for each case. By using a discrete ret after, we can get all three use cases out of "neg x".
Mike
Thanks. I just fixed it.
The word "stalls" suggests that STALLI is used, which is not the case now. I suggest the following:
or
Okay. Will do. Thanks, TonyB_
Maybe? Now I'm worried. What do you mean?
Just suggesting an alternative wording that doesn't involve the word "stall" but still conveys that the interrupt will fire eventually.