Перейти к содержанию
    

Нужна помощь разобраться с asm рутиной FIRа

После долгих моих тугодумных мук родил FIR код в asm который будет част проэкта (вызывается из кода С). Почему-то после добавления ее в проэкт (данного файла asm) - проэкт не компилируется - падает ессно на этой рутине выдавая кучу ошибок. Первая из них весьма странная мне, не могу понять что его не устраивает. Может подскажете чего я не вижу:

 

.mmregs
.global _p_buffer_in,_p_buffer_out,_dline,_fcoeff,_fir_ord,_p_buff_lenth
.global _fir_processing

_fir_processing:
; saving regs content into stack
    pshm ar0; used as delay line and coeff. cycling addressing increment
    pshm ar1; holds input data array start address 
    pshm ar2   ; holds pointer to filter coeff. array addressing
    pshm ar3; holds pointer to delay line array addressing
    pshm ar4; holds output data array start address
    pshm ar5; holds output data array 
    nop
    nop
    
; Initialization
    stm #1,ar0                   ;set increment step for cycling buffers
    mvdm *(_fir_ord),BK          ;set cyclic buffer size (for delay line and coeff buffer)
    stm #_p_buff_in,ar1             ;load data_in array start address
    stm #_fcoeff,ar2             ;load coeff. array start address
    stm #_dline,ar3                 ;load delay line array start address
    stm #_p_buffer_out,ar4         ;load output data buffer array address
    mvdm *(_p_buff_length)-1,brc ;load BRC with processing data block length (PROC_BUFFER_LENGTH)
    nop
    nop
    
; Filtration
    rptb fir_loop_end-1            ; repeat FIR routine for entire processing data buffer
    mvdd *ar1+,*ar3+%          ; load next input sample from input proc. array into delay line array
    
    rptz a,_fir_ord-1            ; FIR order less 1 iterations per each input data sample
    mac *ar2+0%,*ar3+0%,a             ; MAC operation on cyclic delay line and coeff. arrays
    
    rnd a                         ; round off value in acc. A to 16 bits
    sth a,*ar4+                      ; store output value into data output array
  fir_loop_end:
    
    popm ar5
    popm ar4
    popm ar3
    popm ar2
    popm ar1
    popm ar0

 

Первая ошибка которую выдает компилятор:

> ERROR ! at line 29: [E0004] Expecting dual memory addressing

mvdd *ar1+, *ar3+%

 

Дальше еще есть кучу ошибок, подозреваю что некоторые завязаны на предыдущих, посему буду исправлять по одной от первой к последней с перекомпиляцией после каждой.

 

Итак, что ему не нравиться в mvdd ? Она-то вроде перекидывает из памяти в память, и вроде у меня так и есть в коде.... :cranky: Что я в упор не вижу ?????

 

Кроме того, если видите у другие ошибки в коде алгоритма - буду благодарен за указание таковых...

 

P.S. Все переменные в данном asm определены в основном С коде.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 - В mvdd можно использовать только регистры ar2,ar3,ar4,ar5

2 - rnd не стоит использовать т к она работает неправильно читайте эррату на процессор заменить на ADD #1,15,src[,dst]

3 - Загляните в хелп CCS в разделы Register Conventions и Function

Conventions

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 - В mvdd можно использовать только регистры ar2,ar3,ar4,ar5

2 - rnd не стоит использовать т к она работает неправильно читайте эррату на процессор заменить на ADD #1,15,src[,dst]

3 - Загляните в хелп CCS в разделы Register Conventions и Function

Conventions

 

Да, спасибо.

Я вчера рылся в нете насчет инфы по rnd (error подозрительным показался...) и действител-ьно наткнулся на упоминание эрраты, скачал SPRZ 155d - там вторая advisory как раз об этом и говорит. Рекомендуют заменять rnd на то что вы пердложили. Так и сделал в сорсе.

Кстати, вопрос - этот вариант округления результата я видел в примере FIR кода:

http://cnx.org/content/m10023/2.19/, и оттуда его стянул (rnd). Честно говоря не совсем понял резонность такого способа округления до 16 бит. Хелп на rnd говорит о прибавлении к аккумулятору 2^15 степени, затем они там в примере беру как результат старшие 16 бит аккумулятора. е могли бы вы пояснить чайнику каким образом так получаем 16 эффектиных бит (включая знак) ?

 

Насчет mvdd - понял, спасибо. Загляну в conventions. Пока заменил ее на две инструкции переброски данного через аккумулятор Б.

 

Еще одна вещь: при прогоне в дебаггере, обнаружил что:

mvdm *(_p_buff_length)-1,brc

не правильно работает - загружает не то значение которое по адресу _p_buff_length. Не знаю почему (может стоит тоже проверить register conventions), но пока заменяю ее на три другие:

ld *(_p_buff_length), b

sub #1, b

stl b, brc

тут загвоздка - в runе, последняя не загружает brc регистр вообще. Наверно применил не ту инструкцию для загрузки mеmory-mapped регистра из аккумулятора. Как правильно это сделать ?

 

В целом, вам кажется код OK ? Нет каких-либо явных ошибок в имплементации алгоритма ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Conventions описано как праввильно делать вызов асм функций из С, как передать параметры через стэк, и какие регистры использует компилятор для своих нужд (какие регистры требуют сохранения на стэке), а какие можно свободно использовать без сохранения контекста

 

Код смотрел бегло - то что бросилось в глаза и написал

 

Да еще при использовании циклической адрессации в mvdd необходимо использовать ar0 для модификации адресных регистров

типа mvdd *ar2+,ar3+0%

Тогда будет работать

 

mvdm *(_p_buff_length)-1,brc заменить на

mvdk *(_p_buff_length-1),brc

 

По поводу округления - ссылку не смотрел.

Отвечу опираясь на эррату -

здесь округление до соответствующего 2-чного разряда (младшего значащего в формате Q15 (15 - бит дробная часть 1 бит -3нак)), а не десятичного.

Дорустим:

(АH:AL)=0x00008000 = 0.000015259(=0x8000*(1/0x80000000)) в формате Q31.

Добавляем (единицу сдвинутую на 15)-> AH:AL+0x8000=>

(АH:AL)=0x00008000 =0.000015259(q31)

+ 0x00008000 =0.000015259(q31)

(АH:AL)=0x00010000 = 0.000030517578125(Q31)=0x0001(Q15)

То есть берем старшую часть аккумулятора, а младшую отбрасываем в итоге получается верный 16-битный округленный до ближайшего большего результат в формате (Q15) =0x0001

(PS точка находится между msb msb-1 результата как для Q31 так и для Q15)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Conventions описано как праввильно делать вызов асм функций из С, как передать параметры через стэк, и какие регистры использует компилятор для своих нужд (какие регистры требуют сохранения на стэке), а какие можно свободно использовать без сохранения контекста

 

Код смотрел бегло - то что бросилось в глаза и написал

 

Да еще при использовании циклической адрессации в mvdd необходимо использовать ar0 для модификации адресных регистров

типа mvdd *ar2+,ar3+0%

Тогда будет работать

 

mvdm *(_p_buff_length)-1,brc заменить на

mvdk *(_p_buff_length-1),brc

 

По поводу округления - ссылку не смотрел.

Отвечу опираясь на эррату -

здесь округление до соответствующего 2-чного разряда (младшего значащего в формате Q15 (15 - бит дробная часть 1 бит -3нак)), а не десятичного.

Дорустим:

(АH:AL)=0x00008000 = 0.000015259(=0x8000*(1/0x80000000)) в формате Q31.

Добавляем (единицу сдвинутую на 15)-> AH:AL+0x8000=>

(АH:AL)=0x00008000 =0.000015259(q31)

+ 0x00008000 =0.000015259(q31)

(АH:AL)=0x00010000 = 0.000030517578125(Q31)=0x0001(Q15)

То есть берем старшую часть аккумулятора, а младшую отбрасываем в итоге получается верный 16-битный округленный до ближайшего большего результат в формате (Q15) =0x0001

(PS точка находится между msb msb-1 результата как для Q31 так и для Q15)

 

 

OK, спасибо но заменив на mvdk *(_p_buff_length-1),brc ничего не дало, работает так-же ошибочно как и с mvdm (т.е. загружается в BRC ошибочная переменная и единица не вычитается)..

Странно..пока заменил 4мя другими коммандами чтоб работало:

.bss temp, 1
.
.
ld *(_pbuff_length), b
sub #1, b
stl, b, *(temp)
mvdm *(temp), brc

не эффективно, но работает...

 

вернул обратно mvdd *ar2+,ar3+0% (в ar2 -> pointer на массив данных, ar3 -> pointer на линию задержки = 150) - приняло.

Но в дебаггере при runе, вследствии поядка следваания комманд:

mvdd *ar1+,*ar3+%         ; load next input sample from input proc. array into delay line array
rptz a,_fir_ord-1                ; FIR order less 1 iterations per each input data sample
mac *ar2+0%,*ar3+0%,a  ; MAC operation on cyclic delay line and coeff. array

наблюдаю что указатель на линию задержки (в ar3) после каждого люпа (150 итераций) прыгает через 6 адресов (т.в. если первый sample из массива данных он положил по первому адресу линии задержки: 0х2000, то после люпа, след. sample он ложит в 0х2007).

Мне казалось что должна происходить циркуляция по заданному циклу (150), т.е. каждый послед. sample из массива данных должен ложиться в послед. адрес линии задержки (0х2000 -> 0х2001 -> 0х2003 и т.д.). Я не прав ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

mvdk *(_p_buff_length-1),brc сорри Вас запутал и сам заплутал

mvdk *(_p_buff_length-1),brc - такая штука загрузит в брс значение из ячейки с абсолютным адресом (_p_buff_length-1).

 

Поэтому - по адресу _p_buff_length должно лежать сразу нужное значение (на единицу меньше), если хотите использовать

mvdk *(_p_buff_length),brc

 

По поводу циркулярной адрессации и rptz грабли таки

rptz a,_fir_ord-1 , если _fir_ord - адрес внешней константы (в сях), то компилер реально считает, что число повторений следующей инструкции лежит по адресу _fir_ord-1 и выполняет инструкцию это число раз +1 - ничего общего с Вашей задумкой я думаю

=> два способа вызова rptz (Mnemonic insruction Set)

1 rptz a,#_fir_ord-1

повторит след инструкция _fir_ord раз, где _fir_ord - константа объявленная в этом же асме или еще где во внешнем асме чере .set

2 rptz a,*(_fir_ord)

в этом случае повторит след инструкция число раз +1 лежащих по адрес _fir_ord .

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

mvdk *(_p_buff_length-1),brc сорри Вас запутал и сам заплутал

mvdk *(_p_buff_length-1),brc - такая штука загрузит в брс значение из ячейки с абсолютным адресом (_p_buff_length-1).

 

Поэтому - по адресу _p_buff_length должно лежать сразу нужное значение (на единицу меньше), если хотите использовать

mvdk *(_p_buff_length),brc

 

По поводу циркулярной адрессации и rptz грабли таки

rptz a,_fir_ord-1 , если _fir_ord - адрес внешней константы (в сях), то компилер реально считает, что число повторений следующей инструкции лежит по адресу _fir_ord-1 и выполняет инструкцию это число раз +1 - ничего общего с Вашей задумкой я думаю

=> два способа вызова rptz (Mnemonic insruction Set)

1 rptz a,#_fir_ord-1

повторит след инструкция _fir_ord раз, где _fir_ord - константа объявленная в этом же асме или еще где во внешнем асме чере .set

2 rptz a,*(_fir_ord)

в этом случае повторит след инструкция число раз +1 лежащих по адрес _fir_ord .

 

Спасибо, понял.

Пробую: rptz a, *(_fir_ord) не проходит компиляцию - компайлер выдает ошибку утверждая что rptz не принимает indirect addressing.

 

У меня, все глобальные констатнты и определения (включая -fir_ord) определены через главный С файл, посему действительно как вы и говорите нужно indirectt addressing, но засада видимо в том что комманда rptz не принимает indirect.

Неужели нет выхода и нужно в asm коде определять временную переменную и в нее кидать значение _fir_ord данное извне ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ld #0x00,a

rpt *(_fir_ord)

 

rptz действительно не принимает indirect addressing только константы на входе - (сорри спутал с rpt)

Изменено пользователем BratherLU

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ld #0x00,a

rpt *(_fir_ord)

 

ОК, уже скомпилировалось, но при прогоне ар3 адресация (т.е. pointer в линии задержки) прыгает через один адрес при его загрузке (загрузке очередного sample сигнала). Странно, неужели опять не то число циркуляций ?

 

С дургой стороны, заменил ради интереса rptz a, *(_fir_ord) (который не компилировался) на прямое:

rptz a, #150-1 (150 - порядок фильтра) - тогда загрузка в линию задержки в цикле шла нормально, но зато в mac *ar4+0%, *ar3+0%, a поинтер в ar4 (буфер коэффициентов) прыгал меду началом и след. адресом, туда - обратно и не продвигался дальше по буферу. Чего-то я теряю нить... :cranky:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Коэффициенты тоже должны быть выровнены по соответствующей границе

 

Да, так и есть, оба буфера (и коеффициенты и линия задержки выровняны по нужным boundaries (они 150, значит оба буфера выровняны по 256 кратности: один начинается на 0х2000, другой на 0х2100) - это проверено. Это я определил в конфигурации памяти в .cmd (выделил по секции на них, каждая начиная с вышеупомянутых адресов) и соотв. pragmaой в С коде. Так они и сидят.

Не понимаю что ему не хватает, все выровняно, вроде правильная индексация в коде, ... :cranky:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще смотрите - что у вас в BK и в ar0 если все ок значит все таки с числом повторений что-то не то

если BK=число повторений и ar0=1 (-1), то оба указателя должны вернутся в начало буферов после rpt. Не хочу навязывать свои способы, но попробуйте этот цикл организовать через rptb - сможете отследить промежуточные состояния адресных регистров при расчете выборки и отловить ошибку

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще смотрите - что у вас в BK и в ar0 если все ок значит все таки с числом повторений что-то не то

если BK=число повторений и ar0=1 (-1), то оба указателя должны вернутся в начало буферов после rpt. Не хочу навязывать свои способы, но попробуйте этот цикл организовать через rptb - сможете отследить промежуточные состояния адресных регистров при расчете выборки и отловить ошибку

 

Да нет, что-вы, вы ничего не навязываете, ваша помощь очень существенна для новичка типа меня, есть много чему поучиться. :a14:

 

ar0 стабильно держит 1, в BK стабильно сидит загруженное число (150 - порядок фильтра), в BRC стабильно сидит размер буфера входных данных - 1 (буфер у меня 290 samples, в BRC загоняю 289 (0х121)). Хмм, бред какой-то...

 

Кстати, для уточнения: размер линии задержки это порядок фильтра (и кол-во элементов задержки), т.е. для FIRа порядка 150, размер линии задержки (BK) и есть 150, так ? Иногда есть путанница и адже в литературе по DSP длинной фильтра называют то его порядок то кол-во коеффициентов (которое на 1 больше порядка)...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Данной реализации длина линии задержки==число коэффициентов FIR

А так совет пусть не эффективно но наглядно

- отлаживайтесь по частям - добейтесь, чтоб после обсчета ОДНОЙ выборки у Вас указатели внутри буферов оказались там где должны оказаться раз уж взялись за циклическую адрессацию.

Ну типа ->

...

инициализация ar3,ar4,

...

stm #1,ar0

stm #(число коэффициентов FIR),bk

stm #(число коэффициентов FIR -1),brc

ld #0x00,a

nop

nop

...

;//(подгружаем отсчет в линию задержки)

ld #0x00,a

rptb _loop_end-1

mac *ar4+0%,*ar3+0%,a

_loop_end

;//(указатели ar4, ar3 при таком контексте будет такими же как и до rptb)

...

и т.д.

Смотрите в симуляторе как где и что меняется и где заканчивается.

Заведется это - перепишите уже как Вам нравится с использованием rpt внутри и rptb снаружи

На перед скажу, если Ваш FIR считает правильно то подав на вход сигнал - дельта функцию (единичный импульс) на выходе получите вектор коэффициентов фильтра

Изменено пользователем BratherLU

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Данной реализации длина линии задержки==число коэффициентов FIR

А так совет пусть не эффективно но наглядно

- отлаживайтесь по частям - добейтесь, чтоб после обсчета ОДНОЙ выборки у Вас указатели внутри буферов оказались там где должны оказаться раз уж взялись за циклическую адрессацию.

Ну типа ->

...

инициализация ar3,ar4,

...

stm #1,ar0

stm #(число коэффициентов FIR),bk

stm #(число коэффициентов FIR -1),brc

ld #0x00,a

nop

nop

...

;//(подгружаем отсчет в линию задержки)

ld #0x00,a

rptb _loop_end-1

mac *ar4+0%,*ar3+0%,a

_loop_end

;//(указатели ar4, ar3 при таком контексте будет такими же как и до rptb)

...

и т.д.

Смотрите в симуляторе как где и что меняется и где заканчивается.

Заведется это - перепишите уже как Вам нравится с использованием rpt внутри и rptb снаружи

На перед скажу, если Ваш FIR считает правильно то подав на вход сигнал - дельта функцию (единичный импульс) на выходе получите вектор коэффициентов фильтра

 

 

Да, спасибо, так и сделал (проверочную рутину с rptb). по выходу из цикла (_loop_end), ar4 (коефф.) действительно вернулся на начало (0х2100) а вот ar3 (линия задержки) оказалась на 0х2001, т.е. ушла на 1 вперед (ее начало в 0х2000). Но в приципе это кажется логично ибо изначально указатель линии задержки инкрементировался до входа в цикл (mvdd *ar1+,*ar3+%), т.е. он по идее опережает инкремент коеффициентов на 1. Вроде все логично, так ?

Если это правильно - верну обратно "оперативный" вариант и проверю еще раз...

 

Насчет проверки рутины подачей импульса - это вы правы, импульс на входе LTI системы (которой и являются наши фильтры) даст передаточную функцию системы, то бишь коеффициенты фильтра...хороший способ само-проверки...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...