Shop OBEX P1 Docs P2 Docs Learn Events
Assembly P1 to P2 question — Parallax Forums

Assembly P1 to P2 question

I am converting the P1 shift register to P2. I am not an assembly guy by any means.

I am working through it, but I have hit a hurdle I cant get over.

The and line here is the problem.

FlexProp gives the following error:

"error: syntax error, unexpected identifier `nr', expecting instruction modifier"
DAT shift_bits

              mov       count, #8               ' Shift 8 bits (one chip)
.shift_bit

              shl       shiftout, #1            ' Move next bit up out of shiftout 
              and       shiftout, #$100 wc,nr   ' Read MSB; store it in carry flag

              muxnz     outa, srclk             ' Make clock low
              muxc      outa, srdata            ' Output the consumed bit to the shift register
              nop                               ' Let data line settle (this nop is optional)
              muxz      outa, srclk             ' Clock high to latch bit of data
              djnz      count, #.shift_bit      ' Do next bit

shift_bits_ret ret

Comments

  • "nr" is a P1 instruction modifier that means "no result"; it prevents the destination from being modified (the final result is calculated but not written back). It is not present on the P2, so you can't use it there.

    Fortunately for you, "and x, y nr" is equivalent to "test x, y". So to make this work on the P2 just change the "and" instruction to "test" and remove the "nr".
  • JonnyMacJonnyMac Posts: 8,923
    edited 2020-12-14 20:55
    The great thing about the P2 is that it dramatically simplifies dealing with IO and basic looping in assembly -- and you can test assembly without starting a cog (when using Propeller Tool [you can port to FlexGUI after]).

    Give this a try:
    pub shiftout(b)
    
      org
                    rep       #6, #8                                ' repeat 6 instructions 8x
                     drvl     SCLK                                  ' clock low
                     testb    b, #7                         wc      ' get msb (bit7) into C
                     drvc     SDAT                                  ' output C on SDAT pin
                     nop                                            ' let it settle
                     drvh     SCLK                                  ' clock low
                     shl      b                                     ' prep next bit
      end
    
    Note that SCLK and SDAT are pin constants, they are not masks (as required in the P1). The drvx instructions take care of setting the IO level and the pin state to output.
  • So I am now a little confused. AS I see the P2 allows inline assembly.

    Is it better to use inline rather than put it all in the dat section ? I know I have seen some really bad C with in-line assembly that was barely legible. Wouldn't it make readability and maintainability better if it was separated ?
  • RaymanRayman Posts: 13,860
    edited 2020-12-15 22:27
    One great thing about inline assembly is that you don't need a spare cog to run it...


    One bad thing is there are limits to the complexity of the code that can be inline.
  • You can also CALL assembly hubexec blocks from spin2 too.
    Something like this.
    pub main()
    
        pinh(58)
        repeat
           pint(58)
           call(@blink)
    
    
    dat     orgh
    
    blink   drvnot  #56
            waitx ##25_000_000 / 5
            ret
    
    
  • RaymanRayman Posts: 13,860
    ozpropdev wrote: »
    You can also CALL assembly hubexec blocks from spin2 too.

    Wow, is that a new thing? I'm not sure I knew about "CALL".
    Wonder if that works in FlexProp...

  • From the spin2 docs:
    CALL(Addr) CALL PASM code at Addr, PASM code should avoid registers $140..$1D7 and LUT
  • RaymanRayman Posts: 13,860
    I have a feeling that leaves off some needed details...
  • roglohrogloh Posts: 5,158
    edited 2020-12-15 23:38
    CALL(Addr) CALL PASM code at Addr, PASM code should avoid registers $140..$1D7 and LUT

    In cases where the inline PASM code wouldn't fit within $140 longs I expect it should still be possible to just preserve the additional COG registers and LUT RAM that normally needs to be avoided by the called PASM code so you can make even more use of the COG's resources before restoring these registers when it returns back to SPIN2. SETQ[2] transfer bursts would help there. There will be extra overhead for these steps, but in some applications it could still be useful. The HW stack may also need to be preserved if that also needs to be used by the PASM code.

    EDIT. Actually I guess this situation won't really arise due to "not fitting" if this CALL is simply executing in hub-exec mode anyway, more likely to be needed if the inline PASM wanted to use the LUT resource or need more than the first $140 longs for it's data purposes perhaps.
  • Greg LaPollaGreg LaPolla Posts: 319
    edited 2020-12-19 07:45
    Stuck again. Same section of code.

    I know outa can be replaced with drvl. But it doesn't work. I think it has something to do with mux. I don't quite understand what mux does, but if I remove it and just use drvl it compiles ad runs, but I am not getting the expected results.

    I have attached the object for further reference.
    
    shift_bits		mov	count, #8                ' Shift 8 bits (one chip)
    
    .shift_bit		shl	 shiftout, #1            ' Move next bit up out of shiftout 
                 	        test   shiftout, #$100 wc     ' Read MSB; store it in carry flag
    
                     muxnz     outa, srclk             ' Make clock low
                     muxc      outa, srdata            ' Output the consumed bit to the shift register
                     nop                               ' Let data line settle (this nop is optional)
                     muxz      outa, srclk             ' Clock high to latch bit of data
                     djnz      count, #:shift_bit      ' Do next bit
                     ret
    
  • AribaAriba Posts: 2,682
    edited 2020-12-19 12:17
    The shift_bits routine in your attached code looks good.
    The load_ and store_states subroutines need more nop's with P2, I think, but there is a better way for indirect access of cogram on P2:
    store_states   altd    arg1_, #out_states
                   mov     0, shiftout
                   ret
    
    load_states    alts    arg1_, #out_states
                   mov     shiftout, 0
                   ret
    

    But the main question is: Is this just an exercise to learn PASM2, or is your goal a good object for these shift registers?
    In the second case, it makes no sense to start another cog to do some PASM code with the Prop2. There is inline PASM which runs in the same cog, or even better you can use pure Spin2, without PASM for such tasks. Spin2 is much, much faster than Spin on the P1.

    Attached is a Spin2 only version, shifting 1 bit takes under 3us with Chips Spin2 and about 1 us with fastspin at 180MHz sysclock. I have not testet it with real chips, but checked the signals on a scope.

    Andy
  • Greg LaPollaGreg LaPolla Posts: 319
    edited 2020-12-19 15:30
    @Ariba The answer is both. More of the first actually.

    Thanks for the help. I will take a look at it later today.
  • Greg LaPollaGreg LaPolla Posts: 319
    edited 2020-12-26 05:47
    So I did get this working using some code provided by @JonnyMac. Revisiting it again to further drive myself insane.

    looking again at this section:
    and convert it from p1
    why does the and line not work here ? At least I think that is where it breaks

    I am more on a quest to learn assembly at this point!
    shift_bits    mov       count, #8               ' Shift 8 bits (one chip)
    .shift_bit    shl       shiftout, #1            ' Move next bit up out of shiftout 
                  and       shiftout, #$100 wc      ' Read MSB; store it in carry flag
    
                  drvl       srclk                        ' Make clock low
                  drvc      srdata                      ' Output the consumed bit to the shift register
                  nop                                      ' Let data line settle (this nop is optional)
                  drvh	   srclk                        ' Clock high to latch bit of data
                  djnz      count, #.shift_bit      ' Do next bit
    
                  ret
    
  • JonnyMacJonnyMac Posts: 8,923
    edited 2020-12-26 06:14
    How do you know it's not working? An alternative in PASM2 that I think is a little more obvious is testb (see * line).
    shift_bits      mov       count, #8                             ' Shift 8 bits (one chip)
    .shift_bit      shl       shiftout, #1                          ' Move next bit up out of shiftout 
    {*}             testb     shiftout, #8                  wc      ' Read MSB; store it in carry flag
                    drvl      srclk                                 ' Make clock low
                    drvc      srdata                                ' Output the consumed bit to the shift register
                    nop                                             ' Let data line settle (this nop is optional)
                    drvh      srclk                                 ' Clock high to latch bit of data
                    djnz      count, #.shift_bit                    ' Do next bit
                    ret
    
    My habit is to pre-shift the bits so that the shift left can get the MSB into C.
    shift_bits      shl       shiftout, #24                         ' move msb to shiftout.[31]
                    rep       #5, #8                                ' repeat next 5 instructions 8x
                     shl      shiftout, #1                  wc      ' get msb
                     drvl     srclk                                 ' clock low
                     drvc     srdata                                ' write data
                     nop                                            ' let data settle
                     drvh     srclk                                 ' clock high
                    ret
    
    Using rep (repeat), you can save a variable since you're always shifting 8 bits.
  • JonnyMacJonnyMac Posts: 8,923
    edited 2020-12-26 06:14
    I know what's happening. The and line is wiping out the rest of shiftout and only preserving the first bit during the first loop. There is no nr flag in the P2 which is what you need to preserve shiftout in this case. No worries, the testb instruction will do what you want.
  • ozpropdevozpropdev Posts: 2,791
    edited 2020-12-26 06:18
                  and       shiftout, #$100 wc      ' Read MSB; store it in carry flag
    
    The C flag will contain the parity of the result not the msb.

  • ozpropdev wrote: »
                  and       shiftout, #$100 wc      ' Read MSB; store it in carry flag
    
    The C flag will contain the parity of the result not the msb.

    For a single bit (e,g. a mask of $100) the parity and value are the same, which is sometimes convenient.
Sign In or Register to comment.