Page 1 of 1
RMPA Instruction - confusion?
Posted: Sat Mar 13, 2021 12:03 pm
by jwhitmore
There's not a lot to the 'rmpa' instruction. As the SPINAsmUsersManual.pdf states:
"RMPA will fetch the indirectly addressed sample from the delay ram, multiply it by C and add the result to the previous content of ACC"
There's even an example code segment in the manual:
Code: Select all
; Crude variable delay line addressing
sof 0,0 ; Clear ACC
rdax POT1,1.0 ; Read POT1 value
wrax ADDR_PTR,0 ; Write value to pointer register, clear ACC
rmpa 1.0 ; Read sample from delay line
wrax DACL,0 ; Result to DACL and clear ACC
That's fairly clear in so far as it goes, but if you're doing a stereo delay with two delay buffers:
Code: Select all
delay_l mem 8000
delay_r mem 8000
ldax ADCR
wra delay_r, 0
ldax ADCL
wra delay_l, 0
The the description of the 'rmpa' instruction is less clear, "
"RMPA will fetch the indirectly addressed sample from the delay ram". I have two sections of delay memory defined, one for the left channel and one for the right. It's not clear to me how I indirectly address the section of delay memory that I'm interested in, left or right.
Could I complete my stereo delay code with, the 'crude' example given in the manual:
Code: Select all
sof 0,0 ; Clear ACC
rdax POT1,1.0 ; Read POT1 value
wrax ADDR_PTR,0 ; Write value to pointer register, clear ACC
rmpa 1.0 ; Read sample from LEFT delay line
wrax DACL,0 ; Result to DACL and clear ACC
rmpa 1.0 ; Read sample from RIGTH delay line
wrax DACR,0 ; Result to DACL and clear ACC
That doesn't feel right. I guess I'm writing the same sample to the left and right channel?
Re: RMPA Instruction - confusion?
Posted: Sun Mar 14, 2021 8:53 am
by frank
The indirect address would be the base of the delay + any offset.
So if the delay starts at 0x20 and you are using a POT to adjust the offset into the delay from 0 to 0x10 then the indirect address to put into ADDR_PTR would be calculated by 0x20 + (POT * 0x10)
Re: RMPA Instruction - confusion?
Posted: Mon Mar 15, 2021 12:49 pm
by jwhitmore
Thanks Frank but sorry I'm still struggling with it.
I get the indirect addressing mode, I've no problem with that, and the offset stored in the ADDR_PTR register. If we had somehow stored an offset of 0x100 in the ADDR_PTR register that's the required offset, What I'm struggling with is how the code specifies the base address that the offset if applied to. In the case of stereo I have delay_mem_left and delay_mem_right. You might assume that you specify the base address by loading it into the ACC before the RMPA instruction, but offset can't be in the ACC as the contents of delay mem is added to the existing contents of ACC.
Ah hold on this instruction just works on the, unstructured by me, delay memory. So if I split the max delay memory between two channels of delay. Max delay mem is 32K so 0x8000
Code: Select all
delay_l equ $4000
delay_r equ $4000
So if I want to read the offset of 0x100 from each delay channel left and right, if we assume that the first delay memory segment is lower in memory I'd have to load the ADDR_PTR with 0x0000 + 0x100 for the left channel and sizeof(delay_l) 0x4000 + 0x100 to the ADDR_PTR for the right channel. So:
Code: Select all
;; Left Channel
ldax ADCL
wrax delay_l
;; Read from offset 0x100 and write out
ldax $0000 + $100 ; Loading of an immediate value into ACC can't find instruction for it but something like load $100 into ACC
wrax ADDR_PTR, 0
rmpa 1.0
wrax DACL, 0
;; Right channel
ladx ADCR
wrax delay_r
;; Read from the offset 0x100 in the right delay buffer
ldax $4000 + $100
wrax ADDR_PTR, 0
rmpa 1.0
wrax ADDR_PTR, 0
Think I have it now, just have to work out how to get an immediate value 0x1100 into ACC.
Re: RMPA Instruction - confusion?
Posted: Mon Mar 15, 2021 5:24 pm
by frank
You will need to do something like:
Code: Select all
clr ; clear acc
or delay_r*256 ; put base address of delay in acc shifted to align bits for addressing
wrax reg0,0 ; save it
or $4000*256 ; length of delay aligned for addressing into acc
mulx pot0 ; mult by pot for adjustable delay
rdax reg0,1.0 ; add base address
wrax addr_ptr, 0 ; write to address ptr
rmpa 1 ; get sample
Re: RMPA Instruction - confusion?
Posted: Tue Mar 16, 2021 2:00 pm
by jwhitmore
Thanks a million Frank, That's so helpful, the 'or' instruction, I was looking over the instruction set trying to figure out how to load an immediate value into the Accumulator. Never occurred to me to use an or.
Thanks for all your help, think I'm up and running.
John
Re: RMPA Instruction - confusion?
Posted: Thu Apr 08, 2021 2:58 pm
by jwhitmore
The previous answer got me moving, but after some looking I could not find the answer to a couple of questions on the code given. So given the code:
Code: Select all
clr ; clear acc
or delay_r*256 ; put base address of delay in acc shifted to align bits for addressing
wrax reg0,0 ; save it
or $4000*256 ; length of delay aligned for addressing into acc
mulx pot0 ; mult by pot for adjustable delay
rdax reg0,1.0 ; add base address
wrax addr_ptr, 0 ; write to address ptr
rmpa 1 ; get sample
The symbol 'delay_r' is a moving target on each execution that address is moved for each sample. So every execution you can simple read from the ADC and write to 'delay_r'. So whilst I agree with the comment and what it's doing I'm not 100% sure it's doing what the comment suggests.
Secondly I can't find a reference to multiplying that address, and the $4000, but 256. (In my code I had a delay memory size of decimal 4000 so I assume that '$' is a typo.)
The example from page 46 of the SPINAsmUserManual.pdf is even more confusing, where the value of the pot is written on addr_ptr before the rmpa instruction. The Pot value is between zero and 1 so that address is weird, even if you multiplied it by 256.
Re: RMPA Instruction - confusion?
Posted: Fri Apr 09, 2021 2:51 am
by potul
jwhitmore wrote: ↑Thu Apr 08, 2021 2:58 pm
The symbol 'delay_r' is a moving target on each execution that address is moved for each sample. So every execution you can simple read from the ADC and write to 'delay_r'. So whilst I agree with the comment and what it's doing I'm not 100% sure it's doing what the comment suggests.
delay_r is the base address of your delay memory. This is a circular buffer that rolls at each sample cycle. so if you write ADC to delay_r, and read from delay_r+4000, you get a delay of 4000. If you multiply by the pot value(from 0 to 1), you get a variable delay time, from 0 to 4000
Re: RMPA Instruction - confusion?
Posted: Sun Apr 18, 2021 4:50 am
by jwhitmore
potul wrote: ↑Fri Apr 09, 2021 2:51 am
delay_r is the base address of your delay memory. This is a circular buffer that rolls at each sample cycle. so if you write ADC to delay_r, and read from delay_r+4000, you get a delay of 4000. If you multiply by the pot value(from 0 to 1), you get a variable delay time, from 0 to 4000
I get the circular buffer, but I think I'm getting the implementation wrong in my head. I've been imagining that the address delay_r is a circular buffer address which is moving sequentially through the buffer. So if on the first sample delay_r points to address 0x0000 then after 200 samples it points to address 0x00c8. That might be the wrong mental representation, perhaps delay_r is always the same address but the underlying arch moves the memory location being address, so it's like a virtual memory address?
Even in a virtual memory address implementation I'm not sure about multiplying it by a POT value. If delay_r address is 0x0000 you can multiply it by what ever you want and get the same value. I'd be happier if you could multiply the POT by the size of the delay buffer and add it to the base address delay_r. That's just the way I'm abstracting this coming from traditional CPU's rather then DSP.
So if you'd a stereo buffer size 4k and you wanted to use the POT for delay you'd want to be reading delay_l + 4k * POT and delay_r + 4K * POT
To add to the confusion you appear to have to scale the address but 256 so it'd be (delay_l * 256) + ( 4k * POT ) and likewise for delay_r.
Re: RMPA Instruction - confusion?
Posted: Sun Apr 18, 2021 8:55 am
by frank
jwhitmore wrote: ↑Sun Apr 18, 2021 4:50 am
That might be the wrong mental representation, perhaps delay_r is always the same address but the underlying arch moves the memory location being address, so it's like a virtual memory address?
There is a counter that is decremented every sample period that is added to the address in the instruction. This is explained on page 21 of the assembly language PDF.
jwhitmore wrote: ↑Sun Apr 18, 2021 4:50 am
Even in a virtual memory address implementation I'm not sure about multiplying it by a POT value. If delay_r address is 0x0000 you can multiply it by what ever you want and get the same value. I'd be happier if you could multiply the POT by the size of the delay buffer and add it to the base address delay_r. That's just the way I'm abstracting this coming from traditional CPU's rather then DSP.
That is what it does, it multiplies by the length and adds it to the delay base address, the comment in the example code is:
or $4000*256 ;
length of delay aligned for addressing into acc
mulx pot0 ; mult by pot for adjustable delay
jwhitmore wrote: ↑Sun Apr 18, 2021 4:50 am
To add to the confusion you appear to have to scale the address but 256 so it'd be (delay_l * 256) + ( 4k * POT ) and likewise for delay_r.
Yes, there are 8 bits below the address LSB as fractional address bits you could use as interpolation coefficients, etc.