Shop OBEX P1 Docs P2 Docs Learn Events
Using PHSa as a 0-to-15 multiplier — Parallax Forums

Using PHSa as a 0-to-15 multiplier

tonyp12tonyp12 Posts: 1,951
edited 2014-05-08 21:33 in Propeller 1
Question:
After you reset (write to) phsa, the following instruction read of phsa will be 2 ticks higher.
So if frqa is set for 1, after a reset to 0 the following read of phsa be 2.
But I need to make it 4.

This example takes a value and multiply it by 0 to 15 as it keeps adding a phsa value that have kept growing to the ^2 each time.
As you can not tell count-always to div the clock source the total will be 8x on top of 0-15x but not a big deal as I need to align(shift) for Fixed-point arithmetic later on anyway.

I'm trying to create a 4bit (16 level) Attack-Decay-Sustain-Release envelope, so it need to have cycle consistency and be fast
and no single NOP will remain in the end and that phsa auto-increment use this cycle for something productive.
entry         movi  CTRA, #%11111_000                                           ' count always
              movs  label, wavepnt                                              ' get value from sinewave table
              mov   Accumu,#0
label         mov   frqa, 0-0                                                   ' a value from lookup table, a 1 in this example)
              mov   phsa, #0                                                    ' start at at zero but probably need to change
              test  ADSR, #1 wz                                                 ' 4  < a phsa-read yields this, But is 2!!!!!!
       if_nz  add   Accumu,phsa   ' phsa (8x) 1x                                ' 8  < a phsa-read yields this.......                                          
              test  ADSR, #2 wz                                                 ' 12   
       if_nz  add   Accumu,phsa   ' phsa (8x) 2x                                ' 16
              nop                                                               ' 20
              nop                                                               ' 24
              test  ADSR, #4 wz                                                 ' 28   
       if_nz  add   Accumu,phsa   ' phsa (8x) 4x                                ' 32                                                   
              nop                                                               ' 36
              nop                                                               ' 40
              nop  ' instead do something useful                                ' 44
              nop                                                               ' 48
              nop                                                               ' 52
              nop                                                               ' 56
              test  ADSR, #8 wz                                                 ' 60   
       if_nz  add   Accumu,phsa   ' phsa (8x) 8x                                ' 64

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2014-05-08 16:25
    Would preload with 2*frqa help?
    mov     phsa, #0
    [COLOR="#FF8C00"]mov     phsa, phsa[/COLOR]   ' re/set to 2*frqa
    
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-05-08 16:59
    Yes it did, I'm using PST and it's sending the right values to terminal now.
    I knew I needed to get a sinewave value *2 in as a start value, and one extra line is not bad.

    As long I get good use of replacing the NOPs this must be one of the fastest 0-15x multi,
    anyone else with something faster? (consistent cycles is a must)
  • jazzedjazzed Posts: 11,803
    edited 2014-05-08 17:07
    Wouldn't setting CTRA just before doing the actual work help? That is instead of setting CTRA first.
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-05-08 17:22
    No I tried it.
    The trick is to get two cycles in there, and reading psha at cycle 2 and writing that value back at cycle 4 will do the trick as Kuroneko stated above.

    The plan is to use a 256 long look-up table (starting at address 0) that contains three independent 10bit waveforms in each long.
    Use the 9bits and with use multiplication to amplitude it to 13bit range controlled by the ADSR envelope
    The 10th bit is sign flag and will be used with add/sub (eg SUMC probably) it to 14bit accumulator
    So 4cogs *3 channels =12 channels going to a master cog that sum them all up before sending it out to DAC or digitally to a i2s audio driver.
  • kuronekokuroneko Posts: 3,623
    edited 2014-05-08 20:26
    This all being said, why don't you stick with standard multiply unrolled?
    entry           movs    label, wavepnt
                    mov     Accumu, #0
    label           mov     temp, 0-0       ' 1x
    
                    test    ADSR, #1 wz
            if_nz   add     Accumu, temp
                    shl     temp, #1        ' 2x
    
                    test    ADSR, #2 wz
            if_nz   add     Accumu, temp
                    shl     temp, #1        ' 4x
    
                    test    ADSR, #4 wz
            if_nz   add     Accumu, temp
                    shl     temp, #1        ' 8x
    
                    test    ADSR, #8 wz
            if_nz   add     Accumu, temp
    
    temp            res     1
    
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-05-08 20:40
    it's actually 1 instruction longer than mine if you don't include the NOPs
    Yours don't have the side effect of 8x , but if I decide that 4bit decimal point is what I want anyway when I get free shl out of it, bonus another freed up cycle.

    I was trying to get rid of the 3 shl as every cycle is going down with a fight.
    But getting something useful done instead of nop could be harder.

    Wonder if there is a way to do just three test's with 2bits checked each time and use wc wz,
    some type of three branching, probably not.
    loop          movs  label, wavepnt                                              ' get value from sinewave table
                  mov   Accumu,#0
    label         mov   frqa,0-0                                                    ' a value from loopup table, a 1 in this example)
                  mov   phsa,#0                                                     '
                  mov   phsa, phsa                                                  ' rewind it two cycles.
                  test  ADSR, #1 wz                                                 ' 4 (< a phsa-read yields this)           
           if_nz  add   Accumu,phsa   ' phsa (8x) 1x                                ' 8                                                
                  test  ADSR, #2 wz                                                 ' 12   
           if_nz  add   Accumu,phsa   ' phsa (8x) 2x                                ' 16
                  test  ADSR, #4 wz                                                 ' 28   
           if_nz  add   Accumu,phsa   ' phsa (8x) 4x                                ' 32                                                   
                  test  ADSR, #8 wz                                                 ' 60   
           if_nz  add   Accumu,phsa   ' phsa (8x) 8x                                ' 64
    
  • kuronekokuroneko Posts: 3,623
    edited 2014-05-08 20:53
    Can you destroy ADSR? In which case you could use its higher bits as accumulator and do the tests with shr ADSR, #1 wc.
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-05-08 21:05
    I can destroy it, but I decided against it as I can not see that it will save any instructions?

    I was think something weird like:

    test ADSR,#%1010 wc wz
    if_nc_and_z add Accumu,_wave
    test ADSR,#%0101 wc wz
    if_c_and_nz shl Accumu, #2
    test ADSR,#%0011 wc wz
    if_c_and_z sub Accumu,_wave
  • kuronekokuroneko Posts: 3,623
    edited 2014-05-08 21:10
    Let's say the frqx values are all 8n (pre-shifted). Then you could do the following:
    shr     ADSR, #1 wc     ' bit 0
            if_c    add     ADSR, frqx
    
                    shr     ADSR, #1 wc     ' bit 1
            if_c    add     ADSR, frqx
    
                    shr     ADSR, #1 wc     ' bit 2
            if_c    add     ADSR, frqx
    
                    shr     ADSR, #1 wc     ' bit 3
            if_c    add     ADSR, frqx
    
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-05-08 21:33
    I think that can work, as I have to mask out the 10bit wavedata from 3 different locations in a long anyway getting it aligned should not be any extra cycles.
    Explanation: adding a 8x actual wave data, but by doing div2 every time as side effect from getting ADSR data-bits it will be resized down to right values.
Sign In or Register to comment.