Shop OBEX P1 Docs P2 Docs Learn Events
ASM CMP vs TEST INA — Parallax Forums

ASM CMP vs TEST INA

JkaneJkane Posts: 113
edited 2014-10-16 20:36 in Propeller 1
Hello,

Question How to test a pin in propeller asm?

I want to test pin 11 for 1 or 0 in assembler

I was thinking cmp ina,Pin_11, #1 would work but seems not

so I think that is has to be done with a test instruction

Test Value1,Value2 (and compare)

so I would define a mask,

:Pin_11_Bitmask long %00000000_00000000_00001000_00000000

Test ina,P_11, Pin_11 then jump on flags

but this does not work, (ie, I can't get this to work)

regards

Jeff

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2014-10-16 07:14
    You normally use a TEST instruction, but the order of the operands has to be different:

    Use: TEST <mask>,INA wc,wz ' or whatever combination of flags you want

    The reason is that INA is a read-only register and must be specified in the source field of an instruction. If you put it in the destination (first) field of an instruction, what you're really referencing is the COG RAM location (shadow memory) corresponding to the INA register's address. This is also true of other read-only registers like CNT.
  • JkaneJkane Posts: 113
    edited 2014-10-16 07:27
    Thanks

    This is the asm code: The idea is to read bits off pin 11, write the data to an array and then write the array to spin for processing
    :test_init
                 mov addr,par   ' get par address
                 add addr,#28   ' offset by 28 longs
                 rdlong _RX_data,addr 'set or reset RX_data pointer  
                 mov RX_Counter,RX_counter_rst  'reset counter 
                 jmpret Init_P39_ret_P8, #Init_P39_P8   'TX on pin 39
                 
    :read_RX
                 test RX_Test_Msk, ina wz
                 if_ne  jmp :off_bit
                 mov  _RX_data,#1   'set high
                 jmp skip_low
    :off_bit     mov  _RX_data,#0   'set low
    :skip_low    mov addr,#4
                 djnz RX_Counter,#:read_RX  ' loop until the number of subgroups is zero  
                 mov addr, par  ' set address of par
                 add addr, #28   'offset to RX array
                 wrlong  _RX_data,addr 'transmit back to spin
                 jmp#:test_init
    
    
    

    Probably a little messy, but I'll see if it works

    regards

    Jeff
  • tomcrawfordtomcrawford Posts: 1,129
    edited 2014-10-16 08:05
    Remember that longs in hub memory are four apart. So to offset by 28 longs you will have to add 28 * 4.
  • JonnyMacJonnyMac Posts: 9,186
    edited 2014-10-16 08:37
    You have some errors.

    -- As Tom pointed out, the cog sees the hub as an array of bytes, not longs, so you need to update that line, e.g., add addr, #(28 * 4)
    -- jump labels need to be preceded with #, e.g., jmp #skip_low
    -- It appears you want to move the state of the rx pin into rxdata -- I would do this:
    :read_rx                test    rxmask, ina             wc      ' move rx pin to c
                            mov     rxdata, #0                      ' clear rxdata
                            muxc    rxdata, #1                      ' set rxdata to rx input
    


    The second line is a little redundant; if you do it at initialization it doesn't need to be in this loop. You just need to set rxdata to zero before you use this loop.

    Finally... the colon proceeding a label makes it local to the previous simple label; this allows you to use the same generic names in a listing -- like this:
    flash16                 mov     flashes, #10
                            mov     timer, cnt
                            add     timer, p16ontix
    :loop                   or      outa, p16mask
                            waitcnt timer, p16offtix
                            andn    outa, p16mask
                            waitcnt timer, p16ontix
                            djnz    flashes, #:loop
    
    flash17                 mov     flashes, #5
                            mov     timer, cnt
                            add     timer, p17ontix
    :loop                   or      outa, p17mask
                            waitcnt timer, p17offtix
                            andn    outa, p17mask
                            waitcnt timer, p17ontix
                            djnz    flashes, #:loop
    


    The point is: use colons to denote local labels; using them otherwise is an easy way to introduce errors (IMHO).
  • JkaneJkane Posts: 113
    edited 2014-10-16 09:42
    Jon,

    ok,

    on the spin side: rxdata is an array

    long RX_data[128]
    
    

    on the assembler side:
                   mov addr,par  
                   'wrlong _rt,addr
                   add addr,#4
                   mov _Trapz_num,#1
                   wrlong _Trapz_num, addr
                   add addr,#4
                   rdlong  _Sub_grp_size,addr
                   add addr,#4
                   rdlong _Sub_grp_num,addr
                   add addr,#4
                   rdlong  _Sub_grp_time,addr
                   add addr,#4
                   rdlong _Sub_grp_current,addr
                   add addr,#4
                   rdlong _Trapezoid_time,addr
                   add addr,#4
                   rdlong _RX_data,addr
    
                 (_RX_data      res   1  -   last line of the assembler code)
    
    

    so my intention was to capture the status of Pin 11, every 100us, write the status (high or low) to the RX data (which is an array), on both sides. (when I did arrays in assembler on other machines, it was set the absolute base address of the array, load a value, then relative offset the width of the array type (long, int and so on)) to the next position, and in this case loop 128 times and stop.

    then on the spin side print the array.

    so I cleaned up the code, but I'm not sure about the bytes, vs long, when I pass parms to and from asm i use rdlong and wdlong, but updating a array in assembler I use bytes? even if the array is long?
    run_init39
                 mov time, cnt
                 add time, Period100us
                  'xor  outa, Pin10_Pin39        'Make pin 39 high TX transmission
                  mov dira, dira_rx              'dira_RX  long  %00000000_00000000_00001000_00000000          
                  'or   outa,Pin11_Pin26RX    
                  or    outa, Pin17_Trap2        'Turn on led just to check where we are in code  
    :test_init
                 mov addr,par                    ' get par address
                 add addr,#28                    ' offset by 28 longs
                 rdlong _RX_data,addr            'set or reset RX_data pointer  
                 mov RX_Counter,RX_counter_rst   'reset counter to 128
                 jmpret Init_P39_ret_P8, #Init_P39_P8   'TX on pin 39
                 
    :read_RX  ' now start waiting for a reply
                 test RX_Test_Msk, ina wz         'test against mask
                                                  'RX_Test_Msk   long  %00000000_00000000_00001000_00000000  
                 if_ne  jmp #:off_bit             'jump on z flag (a zero bit)
                 mov  _RX_data,#1                 'set high   set array long high
                 jmp #:skip_low                   'already set so skip
    :off_bit     mov  _RX_data,#0   'set low
    :skip_low    add addr,#4*4  'offset in bytes (a long is 4 bytes, the rx_array is a long array, 16 bytes
                 waitcnt    Time, Period100us     ' Wait 100us, then load 100 us        
                 djnz RX_Counter,#:read_RX  ' loop until the number of subgroups is zero  
                 mov addr, par  ' set address of par
                 add addr, #28   'offset to RX array
                 wrlong  _RX_data,addr 'transmit back to spin  - only do it once
    :wait_on_spin
                 
                 jmp#:wait_on_spin  'loop forever and check spin side
    
    

    I originally did this in spin but the timing was not precise enough... so I moved on to asm.

    regards

    Jeff
  • JonnyMacJonnyMac Posts: 9,186
    edited 2014-10-16 11:23
    Jeff,

    I think this can be done in Spin if you structure your code properly. Have a look at the attached test program. It captures the RX pin to a byte array every 100us -- the timed portion of the code (capture loop) took 12824 microseconds. That very small error has to do with initializing t and starting the loop; the time between samples is 100us (using waitcnt and constant).
    pub capture (n, p_buf) | t
    
      t := cnt
      repeat n
        waitcnt(t += constant(US_001 * 100))
        byte[p_buf++] := outa[TX] := ina[RX]
    


    Spin certainly isn't as fast as PASM, but for a 100us loop with very little to do, it's no problem.
  • JonnyMacJonnyMac Posts: 9,186
    edited 2014-10-16 11:36
    Well, here's a funny thing... while I had the code open I decided to test what I considered "clunkier" code -- and it turned out to be faster!
    pub capture | t, n
    
      t := cnt
      repeat n from 0 to 127
        waitcnt(t += constant(US_001 * 100))
        capbuf[n] := outa[TX] := ina[RX]
    


    The last line has changed -- and it's 1.4us faster than the version using pointer and post incrementing (maybe that's where the speed is coming from). Anyway, when one is worried about microseconds, these things matter.

    One of the [many] things I love about the Propeller is that I can use it to explore code style versus performance.
  • JonnyMacJonnyMac Posts: 9,186
    edited 2014-10-16 11:58
    Okay, I have to get back to a VFD driver. If you really want to do it in PASM, I think this shoudl work and is quite clean
    var
    
      long  rxpin
      long  txpin
      long  tix100
      long  bufpntr
    
      byte  capbuf[128]    
    
    
    pub capture
    
      rxpin   := RX
      txpin   := TX
      tix100  := clkfreq / 1_000_000 * 100
      bufpntr := @capbuf
    
      cognew(@cap128, @rxpin)
    
      ' wait for rxin == 0 to signal finished
    
      repeat while (rxpin)
    
      
    dat
    
                            org
    
    cap128                  mov     t1, par                         ' start of parameters
                            rdlong  t2, t1                          ' get rxpin
                            mov     rxmask, #1
                            shl     rxmask, t2
    
                            add     t1, #4
                            rdlong  t2, t1                          ' get txpin
                            mov     txmask, #1
                            shl     txmask, t2
                            test    rxmask, ina             wc      ' sample rx
                            muxc    outa, txmask                    ' copy to tx
                            or      dira, txmask                    ' make tx output
    
                            add     t1, #4
                            rdlong  smpltix, t1                     ' get sample period
    
                            add     t1, #4
                            rdlong  hub, t1                         ' get buffer pointer
    
                            mov     timer, smpltix                  ' start timer
                            add     timer, cnt                      ' sync with system
    
                            mov     cycles, #128
    
    :loop                   waitcnt timer, smpltix                  ' wait sample time, reset timer
                            test    rxmask, ina             wc      ' capture rx to c
                            muxc    outa, txmask                    ' copy to tx
                            mov     t1, #0
                            muxc    t1, #1                          ' t1 = ina[RX]
                            wrbyte  t1, hub                         ' write to array
                            add     hub, #1                         ' advance to next element
                            djnz    cycles, #:loop
    
                            mov     t1, #0
                            wrlong  t1, par                         ' clear rx pin (signal done)
    
                            cogid   t1                              ' self-shutdown
                            cogstop t1               
    
    
    t1                      res     1
    t2                      res     1
    
    rxmask                  res     1
    txmask                  res     1
    smpltix                 res     1
    hub                     res     1
    
    timer                   res     1
    
    cycles                  res     1
    
                            fit
    
  • JkaneJkane Posts: 113
    edited 2014-10-16 13:18
    Jon,

    thanks, code works fine, there is a little offset because my clock is a 6.25, but that is minor.

    regards

    Jeff
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-10-16 14:24
    I see Jon has helped you out.
    But I noticed a few things that might help you understand the prop a little better...
    DAT
                  org       0
    run_init39
                  mov       time, cnt
                  add       time, Period100us
                  'xor      outa, Pin10_Pin39       'Make pin 39 high TX transmission
                  mov       dira, dira_rx           'dira_RX  long  %00000000_00000000_00001000_00000000          
                  'or   outa,Pin11_Pin26RX    
                  or        outa, Pin17_Trap2       'Turn on led just to check where we are in code  
    :test_init
                  mov       addr,par                        ' get par address
                  add       addr,#28                        ' offset by 28 longs
                  rdlong    _RX_data,addr                   'set or reset RX_data pointer  
                  mov       RX_Counter,RX_counter_rst       'reset counter to 128
                  'jmpret   Init_P39_ret_P8, #Init_P39_P8   'TX on pin 39
                  call      #Init_p39_P8            ' rename your return address Init_P39_P8_ret
    :read_RX  ' now start waiting for a reply
                  test      RX_Test_Msk, ina   wz   'test against mask
                                                    'RX_Test_Msk long  %00000000_00000000_00001000_00000000 
    {{ replace the following...
    BTW TEST is performing and AND RX_Test_Msk with ina so Z (eq) means the bit is zero so you have it wrong way around
            if_ne jmp       #:off_bit               'jump on z flag (a zero bit)
                  mov       _RX_data,#1             'set high set array long high
                  jmp       #:skip_low              'already set so skip
    :off_bit      mov       _RX_data,#0             'set low
    }}
            if_z mov        _RX_data,#0             'set low (for a zero bit)
            if_nz mov       _RX_data,#1             'set high set array long high (for a one bit)
                             
    :skip_low     add       addr,#4*4               'offset in bytes (a long is 4 bytes, the rx_array is a long array, 16 bytes
                  waitcnt   Time, Period100us       ' Wait 100us, then load 100 us      
                  djnz      RX_Counter,#:read_RX    ' loop until the number of subgroups is zero
                  mov       addr, par               ' set address of par
                  add       addr, #28               'offset to RX array
                  wrlong    _RX_data,addr           'transmit back to spin - only do it once
    :wait_on_spin
                  jmp       #:wait_on_spin          'loop forever and check spin side
                  
    
  • JonnyMacJonnyMac Posts: 9,186
    edited 2014-10-16 15:23
    That actually works in your favor -- you have more ticks per microsecond, hence can run a few more instructions.

    Jkane wrote: »
    Jon,

    thanks, code works fine, there is a little offset because my clock is a 6.25, but that is minor.

    regards

    Jeff
  • kuronekokuroneko Posts: 3,623
    edited 2014-10-16 20:36
    JonnyMac wrote: »
    pub capture
    
      rxpin   := [COLOR="#FF0000"]NEGX|[/COLOR]RX
      txpin   := TX
      tix100  := clkfreq / 1_000_000 * 100
      bufpntr := @capbuf
    
      cognew(@cap128, @rxpin)
    
      ' wait for rxin == 0 to signal finished
    
      repeat while (rxpin)
    
    In case RX is zero ...
Sign In or Register to comment.