Shop OBEX P1 Docs P2 Docs Learn Events
Initializing asm pointers? — Parallax Forums

Initializing asm pointers?

Peter JakackiPeter Jakacki Posts: 10,193
edited 2006-09-18 17:37 in Propeller 1
I just received my demoboard a couple of days ago and I have been busy modifying sample code etc.
What I want to do is to take microphone samples and store them in a buffer in main memory and playback from the oldest entry to achieve an audio delay.
Being very new at this the problem I am having at the moment is getting SPIN to pass the buffer address as a constant to init the assembly buffer pointer.
Just playing but I think that's right.

Can anyone give me a few pointers?

Thanks,
*Peter*

CON
  sndsz = 4000
  attenuation = 0
  sndbufcon = sndbuf            '!!!!!!!!!!!!! how do i pass the address of sndbuf to assembler?

VAR
  word sndbuf[noparse][[/noparse]sndsz]

  
DAT

'
'
' Assembly program
'
              org

asm_entry     mov       dira,asm_dira                   'make pins 8 (ADC) and 0 (DAC) outputs
'setup ADC
              movs      ctra,#8                         'POS W/FEEDBACK mode for CTRA
              movd      ctra,#9
              movi      ctra,#%01001_000
              mov       frqa,#1
'setup DAC
              movs      ctrb,#10                        'DUTY DIFFERENTIAL mode for CTRB
              movd      ctrb,#11
              movi      ctrb,#%00111_000
              mov       sndptr,sndptrvar
              mov       asm_cnt,cnt                     'prepare for WAITCNT loop
              add       asm_cnt,asm_cycles
:loop         waitcnt   asm_cnt,asm_cycles              'wait for next CNT value (timing is determinant after WAITCNT)
              mov       asm_sample,phsa                 'capture PHSA and get difference
              sub       asm_sample,asm_old
              add       asm_old,asm_sample
'delay buffer (Q&D)
              wrword    @sndptr,asm_sample              'buffer the current sample
              add       sndptr,#2                       'bump ptr
              cmp       sndptr,sndszvar                 'end of buffer?
if_ae         mov       sndptr,sndptrvar                'yep, reset ptr
              rdword    asm_sample,@sndptr              'read oldest sample
              shl       asm_sample,#32-bits-attenuation 'justify sample and output to FRQB
              mov       frqb,asm_sample
              jmp       #:loop                          'wait for next sample period
'
'
' Data
'
asm_cycles    long      |< bits - 1                     'sample time
asm_dira      long      $00000E00                       'output mask

asm_cnt       res       1
asm_old       res       1
asm_sample    res       1

sndptr        res       1
sndszvar      long      sndbufcon+sndsz
sndptrvar     long      sndbufcon

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2006-09-14 14:44
    I haven't looked at the details of your sound conversion, but your use of rdword and wrword is incorrect. I saw the use of "@" and immediately thought "that doesn't belong there". If you look at the description of both instructions, the source field (rightmost operand) is always a HUB address so the "@" isn't needed. Without the "@", the rdword would be correct. If you reverse the operands (wrword asm_sample,sndptr) the wrword should work as well. Try it.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-09-14 19:07
    The most common means for passing a pointer from Spin to assembly is through the PAR register. This is done when starting the assembler cog like so:

    cognew(@asm_entry, @sndbuf)

    This will place the address of sndbuf[noparse][[/noparse]0] into the PAR register of the cog. To use the value (since·PAR is a read only register), copy it into sndptr with:

    mov sndptr, par

    You can also pass it by assigning sndptr via Spin before you run cognew, so you would do:

    sndptr := @sndbuf
    cognew(@asm_entry,0)

    But in your case I would use the PAR method, this way you will keep a permanent read-only copy of the pointer to the buffer that you can reinitialize sndptr if needed.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2006-09-15 13:13
    Paul, I finally got back to that bit of sound buffering code and implemented the PAR method.

    Besides this I learned:
    1. unlike the normal assembler words where the destination is to the left and source to the right instructions such as WRWORD must have the destination address on the right (doh!).

    2. CMP instructions will happily compare but will keep it a secret unless you give them the WZ WC WR options (doh!)

    I am sure I will say doh a few more times yet but this is what I have found. I have included the working code for anyone who is interested.

    *Peter*


    ' This program uses the Propeller Demo Board, Rev C
    ' The microphone is digitized and the samples are played on the headphones.
    ' PBJ:
    ' As an exercise I have modified this program to use a buffer to delay samples
    ' and also to introduce some echo.
    '  
    CON
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    
    ' At 80MHz the ADC/DAC sample resolutions and rates are as follows:
    '
    ' sample   sample               
    ' bits       rate               
    ' ----------------              
    ' 5       2.5 MHz               
    ' 6      1.25 MHz               
    ' 7       625 KHz               
    ' 8       313 KHz               
    ' 9       156 KHz               
    ' 10       78 KHz               
    ' 11       39 KHz               
    ' 12     19.5 KHz               
    ' 13     9.77 KHz               
    ' 14     4.88 KHz               
                                    
      bits = 13               'try different values from table here
      
    
    PUB go
      cognew(@asm_entry, @sndbuf)   'launch assembly program into a COG
    
    
    CON
      sndsz = 16000
      attenuation = 0
    
    VAR
      word sndbuf[noparse][[/noparse]sndsz]
    
      
    DAT
    
    '
    '
    ' Assembly program
    '
                  org
    
    asm_entry
                  mov       sndptr, par
                  mov       sndend,par
                  add       sndend,sndszvar
                  mov       dira,asm_dira                   'make pins 8 (ADC) and 0 (DAC) outputs
    'setup ADC
                  movs      ctra,#8                         'POS W/FEEDBACK mode for CTRA
                  movd      ctra,#9
                  movi      ctra,#%01001_000
                  mov       frqa,#1
    'setup DAC
                  movs      ctrb,#10                        'DUTY DIFFERENTIAL mode for CTRB
                  movd      ctrb,#11
                  movi      ctrb,#%00111_000
                  mov       asm_cnt,cnt                     'prepare for WAITCNT loop
                  add       asm_cnt,asm_cycles
    :loop         waitcnt   asm_cnt,asm_cycles              'wait for next CNT value (timing is determinant after WAITCNT)
                  mov       asm_sample,phsa                 'capture PHSA and get difference
                  sub       asm_sample,asm_old
                  add       asm_old,asm_sample
    'delay buffer
                  rdword    buf,sndptr                      'read oldest sample (for echo)
                  shr       buf,#2                          'attenuate it
                  add       asm_sample,buf                  'and mix it in with the latest
                  wrword    asm_sample,sndptr               'buffer the current sample
                  add       sndptr,#2                       'bump ptr
                  cmp       sndptr,sndend wz                'end of buffer?
    if_e          mov       sndptr, par                     'yep, reset ptr
                  rdword    asm_sample,sndptr               'read oldest sample
                  shl       asm_sample,#32-bits-attenuation 'justify sample and output to FRQB
                  mov       frqb,asm_sample
                  jmp       #:loop                          'wait for next sample period
    '
    '
    ' Data
    '
    asm_cycles    long      |< bits - 1                     'sample time
    asm_dira      long      $00000E00                       'output mask
    sndszvar      long      sndsz
    
    asm_cnt       res       1
    asm_old       res       1
    asm_sample    res       1
    buf           res       1
    
    sndptr        res       1
    sndend        res       1
    
    
    
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-09-15 15:49
    Yes as Mike pointed out the hub memory access routines have the source and destination locations reversed.

    wr is the only default enabled affect flag and this is for instructions that inherently want to write a result, probing instructions such as TEST and CMP have no default affects, wz and wc must always be specified for any instruction you want those flags affected. This may seem crazy to people use to the Intel or Motorola instruction sets, but the conditional affect coupled with the conditional execution is very powerful in reducing code bloat. Notice there are no 'skip if...' instructions as there are in the SX, conditional execution makes them obsolete along with the memory location required for the instruction.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2006-09-15 17:53
    Peter Jakacki,

    Don't forget about using 'nr' as well... this is a way that you can do a non standard comparison without affecting the destination register. For example...

           sub DataValueA,  DataValueB   wz, nr
     if_z  jmp #DataEqual
    
    



    The first line subtracts DataValueA from DataValueB ... If they are equal, then the Zero flag is set ...nr tells the compiler not to write the result back to DataValueA, so DataValueA and DataValueB remain intact.
    The Second line branches to #DataEqual if the Zero flag has been set.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 9/15/2006 5:57:27 PM GMT
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2006-09-16 02:47
    Yes, I saw all the effects settings and along with the conditional operators I can see that each opcode can be quite flexible. Mind you I think that with the current encoding that the cog is limited to 512 32-bit word addressing so I don't think we will see one that has more directly addressable memory than this. It may simply mean that future props have more main memory and more cogs, am I right?

    I missed that point that Mike made and found out fairly quickly anyway. The compile/download/execute cycle is extremely short so it is nothing at all to make a slight change, even without saving and then hitting F10, it works brilliantly, well done!

    The idea of learning and using Spin was not immediately entertained but because the propeller ide is dealing with objects in source code form it makes it very easy to use, investigate, debug, and adapt. There are many many projects I have NOW lined-up for the propeller, I know it's new but why hasn't it taken off faster than this? It is true that there are many that find it hard to change processors and tools (taught on XYZ n C n I'll die XYZ n C [noparse]:)[/noparse] ), but really that's their loss.

    *Peter*
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-09-18 17:37
    Most new concepts take a while before they see wide-spread adoption. It took almost two decades before C became the standard programing language, when I was in college in the early 90s was when CIS course material started adopting C as the language of choice, before then Pascal was the default language.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
Sign In or Register to comment.