MPASM 5.77 PCPWM_3F_4431.ASM 3-22-2020 13:50:44 PAGE 20 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0000B4 00090 NoLim12 ; Делаем из 16 бит 12 00091 #ifdef PCPWM_DC_Corr ; 22/03/2020 добавил опцию 00092 ; movff16 PCPWM_ML_Work+2,DeBug_BufLcd+0 ; Отладочная замена 00093 ; 20/03/2020 Добавка умножения для коррекции амплитуды 00094 ; Умножаем 16*16 амплитуду на номинальное+0x7F и полученные 32 бита 00095 ; делим на 16 бит АЦП накопитель. Полученные 16 бит заменяют амплитуду. 00096 ; 00097 movlf 0x7F,PCPWM_ML_Work+4,bnk ; Мл байт номинала DC 0000B4 0E7F M movlw 0x7F ; в регистр с 7р адресом на 0000B6 6F96 M movwf PCPWM_ML_Work+4,bnk ; текущей странице File7 0000B8 C15E F197 00098 movff PcDC_VN,PCPWM_ML_Work+5 ; Ст байт множителя А 00099 ; Перед умножением PCPWM_ML_Work+2|3,bnk = вычисленная амплитуда 16 бит 00100 ; PCPWM_ML_Work+4|5,bnk = номинальное DC 16 бит 00101 ; PCPWM_ML_Work+6|7,bnk = неизвестно что, будет записан результат умножения старшие байты 00102 00103 FXM1616U2 PCPWM_ML_Work+4,bnk ,PCPWM_ML_Work+4,bnk ,PCPWM_ML_Work+2,bnk, PCPWM_ML_Work+0,bnk ; M ; Кириллика в наименовании переменных макроса неожиданно выводит ошибку 106 "строка подстановки слишком сложна" M ; Результат будет D=A*B ; Умножение 16*16 без знаковое, M ; A и В сохраняется без изменений M ; Результат можно в А засылать если А 4 байта. M ; Необходим 1 байт буферок для промежуточного хранения M ; MULW: ;Multiplication 16bit * 16bit -> 32bit M ;detailed: M ; A_Arg+1:A_Arg+0 * B_Arg+1:B_Arg+0 -> A_Arg+3:A_Arg+2:A_Arg+1:A_Arg+0 M ; B_Arg value remains. Affected registers: 1 byte temp reg M ; Примерно 29 тактов, примерно столько же слов ПЗУ M 0000BC 5197 M movf PCPWM_ML_Work+4+1,w,bnk ; Старшие байты 0000BE 0395 M mulwf PCPWM_ML_Work+2+1,bnk ; B_Arg+1 * A_Arg+1 0000C0 CFF4 F199 M movff PRODH,PCPWM_ML_Work+4+3 ; перемножаем, получаем 0000C4 CFF3 F198 M movff PRODL,PCPWM_ML_Work+4+2 ; старшие байты результата M 0000C8 5196 M movf PCPWM_ML_Work+4+0,w,bnk ; Младшие байты 0000CA 0394 M mulwf PCPWM_ML_Work+2+0,bnk ; B_Arg+0 * A_Arg+0 0000CC CFF4 F192 M movff PRODH,PCPWM_ML_Work+0 ; перемножаем, получаем 0000D0 CFF3 F196 M movff PRODL,PCPWM_ML_Work+4+0 ; Младшие байты результата, M ; однако второй байт результата через буфер ибо нужен ещё M ; A_Arg+0 in WREG unchanged 0000D4 0395 M mulwf PCPWM_ML_Work+2+1,bnk ; B_Arg+1 * A_Arg+0 0000D6 50F3 M movf PRODL,w,ACCESS ; Средние байты множим, прибавляем 0000D8 2792 M addwf PCPWM_ML_Work+0,f,bnk ; Add cross 0000DA 50F4 M movf PRODH,w,ACCESS ; products 0000DC 2398 M addwfc PCPWM_ML_Work+4+2,f,bnk ; к накопителю результата со смещением в 1 байт 0000DE 6AE8 M clrf WREG,ACCESS ; с учётом переноса 0000E0 2399 M addwfc PCPWM_ML_Work+4+3,f,bnk ; M 0000E2 5197 M movf PCPWM_ML_Work+4+1,w,bnk ; Старший байт А ещё не изменялся 0000E4 0394 M mulwf PCPWM_ML_Work+2+0,bnk ; B_Arg+0 * A_Arg+1 0000E6 50F3 M movf PRODL,w,ACCESS ; Средние байты множим, прибавляем 0000E8 2592 M addwf PCPWM_ML_Work+0,w,bnk ;Add cross 0000EA 6F97 M movwf PCPWM_ML_Work+4+1,bnk ; 0000EC 50F4 M movf PRODH,w,ACCESS ; products 0000EE 2398 M addwfc PCPWM_ML_Work+4+2,f,bnk ; к накопителю результата со смещением в 1 байт 0000F0 6AE8 M clrf WREG,ACCESS ; с учётом переноса 0000F2 2399 M addwfc PCPWM_ML_Work+4+3,f,bnk ; M 00104 ; movff_N PCPWM_ML_Work+4,PcDC_Amp+0,4 ; Буферируем для вывода 00105 ; FXM1680U C_Arg,BANKED ,A_Arg,BANKED ,B_Arg,BANKED;, Math_Work+3,BANKED ; 00106 ; C=А*B, А и В сохраняются неизменными 00107 ; Новый макрос могет в качестве АргС иметь АргА (приемник одинаков с источником) 00108 ; а могет и копировать в другие адреса. 00109 00110 ; FXD3216U macro A_Arg,A1A,B_Arg,A1B,_Work,A1W; ; Подразумевается в памяти Младший-Старший байт идут 00111 ; АргументА 4 байта - 32 бита делимое и 16 бит результат в младших байтах, (+остаток в старших закоменти л) 00112 ; Остаток также в _Work+0:+1 00113 ; АргументБ 2 байта - делитель остаётся неизменным 00114 ; При переполнении 4 байта аргумента А = 0xFF 00115 ; Требуются 4 байта рабочей переменной _Work,A1W 00116 ;Unsigned Division 32bit / 16bit -> 16bit + 16bit 00117 00118 ; Перед делением PCPWM_ML_Work+4|7,bnk = результат умножения 00119 ; PCPWM_ML_Work+0|3,bnk - ничего нужного, можно использовать как раб буфер деления 00120 FXD3216U PCPWM_ML_Work+4,bnk,PcDC_ADC+0,bnk,PCPWM_ML_Work+0,bnk; ; Подразумевается в памяти Младший-Ста рший байт идут M ; АргументА 4 байта - делимое и результат + остаток M ; Остаток также в _Work+0:+1 M ; АргументБ 2 байта - делитель остаётся неизменным M ; При переполнении 4 байта аргумента А = 0xFF M ; Требуются 4 байта рабочей переменной _Work,A1W M ;Unsigned Division 32bit / 16bit -> 16bit + 16bit M ;EXTWRD / LUK -> WRD, remainder -> EXT M ;detailed EXT_H:EXT_L:WRD_H:WRD_L / LUK_H:LUK_L -> WRD_H:WRD_L M ;On overflow or divide by zero: FFFFh -> WRD, FFFFh -> EXT M ;LUK value remains. Affected registers: temp reg Math_Work+0,BANKED, M ; Math_Work+1,BANKED, Math_Work+2,BANKED, Math_Work+3,BANKED 0000 M local D32_Loop,D32_3,D32_4,D32_NextShift,D32_OverFlow,D32_End; M ; Step_0; ; DIV32: AN617 Page 13 FlowChart Comments 0000F4 6B92 M clrf PCPWM_ML_Work+0+0,bnk ; TEMP 24 бита 0000F6 6B93 M clrf PCPWM_ML_Work+0+1,bnk ; Clear Reminder 0000F8 6B94 M clrf PCPWM_ML_Work+0+2,bnk ; Partial Quotient= ; неполный результат M ; = Dividend ; Делимое 0000FA 0EE0 M movlw 0xE0;-32; ;LOOPS ;;i=0 ; Начальное значение инкремируемого M ; счётчика циклера = -32. Оно проверяется посередине для каких-то действий. M ; Циклер закончится в момент равенства нулю. 0000FC 6F95 M movwf PCPWM_ML_Work+0+3,bnk ; M M ; Добавка от дружественной многозадачности - M ; incf Math_Step,F,BANKED ; След шаг "проги" заносим для возврата в него M M ; retlw 0x0 0000FE M D32_Loop; SHIFT R8R6R4<<1; : M ; Начало циклера сдвигов/вычитаний/сравнений/занесения битов в результат 0000FE 90D8 M bcf _C ; Входной перенос чистка 000100 3796 M rlcf PCPWM_ML_Work+4+0,f,bnk ; Left Shift ; Сдвигаем влево 000102 3797 M rlcf PCPWM_ML_Work+4+1,f,bnk ; reminder ; остаток и 000104 3798 M rlcf PCPWM_ML_Work+4+2,f,bnk ; and ; будущий 000106 3799 M rlcf PCPWM_ML_Work+4+3,f,bnk ; quotient ; результат 000108 3792 M rlcf PCPWM_ML_Work+0+0,f,bnk ; Я так понял что 00010A 3793 M rlcf PCPWM_ML_Work+0+1,f,bnk ; в раб регистрах есть 00010C 3794 M rlcf PCPWM_ML_Work+0+2,f,bnk ; будущий остаток от деления M ;update _Work+1,2=_Work+1,2-LUK if remains positive 00010E 515F M movf PcDC_ADC+0+0,w,bnk ; Substract Divisor ; Вычитаем Делитель M ; Пробное вычитание 000110 5F92 M subwf PCPWM_ML_Work+0+0,F,bnk ; from partial ; из будущего остатка 000112 5160 M movf PcDC_ADC+0+1,w,bnk ; Reminder ; результата деления 000114 5993 M subwfb PCPWM_ML_Work+0+1,W,bnk ; 000116 E2?? M bc D32_4 ;borrow = !carry ; Result >0 ? ; Результат >0 ? M ;16 bit subtraction < 0 ; В чём выгода вычитать вначале 2 байта а потом ещё 1 ? M ; Быть могет выгода в простоте "restore partial quotient" ? M ; А Если вычитать все байты c результатом во WREG M ; (нас интересует лишь факт конечного заёма), то можно вообще не откатывать ? M ; Проверил 20/03/2020 - ошибки деления идут. 000118 6794 M tstfsz PCPWM_ML_Work+0+2,bnk ; средне-старший байт 00011A D??? M bra D32_3 ;borrow from _Work+2 M ;24 bit subtraction < 0 M ;restore _Work+0 (_Work+1 is already unсhanged) 00011C 515F M movf PcDC_ADC+0+0,w,bnk ; Делаем действие 00011E 2792 M addwf PCPWM_ML_Work+0+0,F,bnk ; обратное вычитанию 000120 D??? M bra D32_NextShift ; парой строк выше, LSB=0 уже (всегда) M ; 000122 M D32_3 000122 0794 M decf PCPWM_ML_Work+0+2,F,bnk ;update _Work+2 старший байт 000124 M D32_4 000124 6F93 M movwf PCPWM_ML_Work+0+1,bnk ;update _Work+0 (_Work+2 is already updated) 000126 8196 M bsf PCPWM_ML_Work+4+0,LSB,bnk ; LSB=1 M ; Тестирование 4 бита отрицательного инкремируемого до 0 счётчика M ; Не проще тестировать старшие байты на равенство нулю ? 000128 A995 M btfss PCPWM_ML_Work+0+3,4,bnk ;>=16 counts remaining? 00012A D??? M bra D32_OverFlow ;overflow M ; M ;next loop 00012C M D32_NextShift 00012C 3F95 M incfsz PCPWM_ML_Work+0+3,f,bnk ; 00012E D??? M bra D32_Loop ; 000130 D??? M bra D32_End ; M ; incfsz Math_Work+3,f,BANKED M ; retlw 0x0 ; Через опрос основного цикла M ; M ;ready, result ok M ; Остаток можно забирать из _Work+0 если он интересен M ; movff _Work+0,A_Arg+2 ;remainder M ; movff _Work+1,A_Arg+3 ; M M ;D32_Return M ; movff FXD3216U_Return,Math_Step; M ; retlw 0x0 ; Через опрос основного цикла M ; M ;overflow 000132 M D32_OverFlow ;movlw 0FFh 000132 6996 M setf PCPWM_ML_Work+4+0,bnk ; Ставим 000134 6997 M setf PCPWM_ML_Work+4+1,bnk ; результаты 000136 6992 M setf PCPWM_ML_Work+0+0,bnk ; при переполнении 000138 6993 M setf PCPWM_ML_Work+0+1,bnk ; 00013A 80D8 M bsf _C ; выходной перенос/переполнение M ; bra D32_Return 00013C M D32_End M 00121 ; movff_N PCPWM_ML_Work+4,PcDC_Amp+4,4 ; Буферируем для вывода 00122 00123 ;Con16v12 MACRO Destin,AdrD,Source,AdrS ; Преобразование 16 в 12 бит 00124 Con16v12 PCPWM_ML_Work+0,BANKED,PCPWM_ML_Work+4,BANKED ; M ; Не могу сообразить сможет ли результат быть источником 00013C 3996 M swapf PCPWM_ML_Work+4+0,W,BANKED ; Младший нибл стал младшим в Акб 00013E 0B0F M andlw 0x0F ; чистим старший нибл Акб 000140 6F92 M movwf PCPWM_ML_Work+0,BANKED ; Буферизуем результат младшего нибла 000142 3997 M swapf PCPWM_ML_Work+4+1,W,BANKED ; Старший байт адреса с поменянными ниблами в Акб 000144 0BF0 M andlw 0xF0 ; чистим младший нибл Акб 000146 1392 M iorwf PCPWM_ML_Work+0,F,BANKED ; Средний нибл в младшем байте указателя 000148 3997 M swapf PCPWM_ML_Work+4+1,W,BANKED ; Старший байт адреса с поменянными ниблами в Акб 00014A 0B0F M andlw 0x0F ; чистим старший нибл Акб 00014C 6F93 M movwf PCPWM_ML_Work+0+1,BANKED ; Старший нибл в старшем байте указателя. 00125 #else;#ifdef PCPWM_DC_Corr ; 22/03/2020 добавил опцию 00126 Con16v12 PCPWM_ML_Work+0,BANKED,PCPWM_ML_Work+2,BANKED ; 00127 #endif; #ifdef PCPWM_DC_Corr ; 22/03/2020 добавил опцию