INCMOD P2 Instruction
 tomcrawford            
            
                Posts: 1,129
tomcrawford            
            
                Posts: 1,129            
            
                    I couldn't find a description anywhere of the P2 Incmod instruction, so I decided to fiddle with it.  Here is the program I used:
It adds one to the destination and compares the result to the source. It compares the source to the destination and if they are the same, it sets the destination to 0 and sets both flags (if wcz). If they are NOT equal, it increments the destination and resets both flags (if wcz). I had thought it might do a real modulo (5 mod 4 = 1), but on thinking about it, realized that would have required a division. So it does something besides just increment only in the one case of equality. I figure decmod is similar.
                            CON            
    oscmode = $010c3f04               'all the standard stuff
    freq    = 160_000_000     
    baud = 230400
    #62, tx_pin, rx_pin
           
OBJ
   ser: "spin/SmartSerial"  
var
    long  command                   '31..16: current, '15..0 modulo                                    
    long status[3]                  'result, zero flag, carry
    long param[2]                   'pass addresses to cog
    byte cog, x
      
pub main
     clkset(oscmode, freq)
     ser.start(rx_pin, tx_pin, 0, baud)       'start up serial terminal
     ser.str(string("hello, world"))
     ser.nl
     param[0] := @command
     param[1] := @status
     command := 1                         'pasm cog will clear this when ready 
     cog := cognew(@entry, @param)        'send ADDRESS of param list
     repeat until command == 0            'wait for cog to get started
     ser.str(string("cog started: "))
     ser.dec(cog)
     ser.nl
     repeat x from -1 to 18       'try a bunch of values
       doit(x, 11)
     repeat                       'stay alive  
pub  doit(value, modulo)
     command := value<<16 | modulo       'send inputs to PASM cog
     repeat until command == 0           'wait until he is done
     ser.nl                              'now display everthing
     ser.str(string("Input Value: "))
     ser.dec(value)
     ser.str(string("   Modulo: "))
     ser.dec(modulo)
     ser.str(string("   Result: "))
     ser.dec(status)
     ser.str(string("   ZeroFlag: "))
     ser.dec(status[1])
     ser.str(string("   Carry: "))
     ser.dec(status[2])
                 
DAT
entry     ORG 0
          rdlong CmdAdrs, ptra++          'address of command
          rdlong Stat0Adrs, ptra          'status in hub (I will return results here)
          wrlong zero, CmdAdrs            'report cog is started
tarry     rdlong MyCommand, CmdAdrs wz    'await a set of parameters
    if_Z  jmp #tarry
          mov ptra, Stat0Adrs             'nice fresh copy of status address   
          mov dest, MyCommand             'isolate parameters
          sar dest, #16
          mov source, MyCommand
          and source, ##$FFFF
          incmod dest, source wcz         'execute it
          wrlong dest, PTRA++             'the result   
   if_C   wrlong one, PTRA++              'and the flags
  if_NC   wrlong zero, PTRA++
   if_Z   wrlong one, PTRA
  if_NZ   wrlong zero, PTRA
          wrlong zero, CmdAdrs            'and we are done
          jmp #tarry  
 
Zero      long  0 
One       long  1
Cmdadrs   res  1             'address in hub memory of command
stat0Adrs res  1             'address of first servo's status              
MyCommand res  1             'current command
dest      res  1
source    res  1
It adds one to the destination and compares the result to the source. It compares the source to the destination and if they are the same, it sets the destination to 0 and sets both flags (if wcz). If they are NOT equal, it increments the destination and resets both flags (if wcz). I had thought it might do a real modulo (5 mod 4 = 1), but on thinking about it, realized that would have required a division. So it does something besides just increment only in the one case of equality. I figure decmod is similar.

 
                            
Comments
It would be better called INCWRAP, or something, to avoid any MODulus confusion.
[ column F ]
Yes, they probably should be renamed, especially to get away from the incorrect use of modulus rather than modulo, and also to cover the fact that if D > S the operation performed isn't a true modulo operation no matter how modulo is interpreted.
Given the comparison occurs before the increment or decrement I'd suggest something more like WRAPINC and WRAPDEC, or WRAP++ and WRAP-- if that isn't seen as too 'C-like'.
which is what the instructions do - so long as the counter starts off modulo N, it remains so - the
operation is closed modulo N.
The confusing bit is that the source operand is interpreted as N-1, not N, but that feature allows the instruction
to work when N = 2^32.
.. but did you check the details of the exact numeric range of that MOD operator ?
Type MOD into your calculator, and you see N MOD M does not include M, it is 0..M-1
Either is fine for me..
Did you read what I said? I said the confusing thing about incmod is that the source operand
denotes N-1, not N as might be expected (until you realized that the way it is allows N to
equal 2^32, and avoids the issue of mod zero being meaningless since you can't denote N=0).
indeed it is and bit me hard with my buffer routines.
Mike
That is exactly why it needs a change of name.
Wrap is probably better.
DECWRAP
Might be nice to have INC and DEC instruction aliases...
Too bad it takes 2 clocks to get -1 into S... Better with ADD, SUB...
Ok, never mind, this is nonsense...
Of course, that begs the question on whether two operations on D are possible during one instruction or if there's room to hold an intermediate result before the final assignment -- if, in fact, the result is to be written.
-Phil
That's fine.
There is no time to do two things, and an equals tests is the simplest/fastest test in logic.
That's why the opcode tests for ==, and then decides whether to INC or wrap to zero, of course, that simplicity means the sweep range includes the == value, which MOD does not, and that's why the name change is needed.
-Phil