Вызов функции сборки PIC

Я пишу довольно простую программу на ассемблере PIC18. Это требует, чтобы я написал подпрограмму для умножения двух 16-битных чисел. Это то, что у меня есть прямо сейчас:

;***********************************************************************
; mul_16bit: subroutine that multiplies two 16 bit numbers stored in
;    addresses mul_16ptr1, mul_16ptr1+1 and mul_16ptr2,mul_16ptr2+1 and
;    returns the 32-bit result in addresses mul_16res1 to mul_16res1+3

;***********************************************************************
mul_16bit:
             movf    mul_16ptr2, W           ;multiply the lower bytes
             mulwf   mul_16ptr1, W
             movff   PRODH, mul_16res+1
             movff   PRODL, mul_16res
             movf    mul_16ptr2+1, W                 ;multiply upper bytes
             mulwf   mul_16ptr1+1, W
             movff   PRODH, mul_16res+3
             movff   PRODL, mul_16res+2
             movf    mul_16ptr2, W           ;multiply lower byte of num2
             mulwf   mul_16ptr1+1, W       ; and upper byte of num1
             movf    PRODL, W
             addwf   mul_16res+1, F
             movf    PRODH, W
             addwfc  mul_16res+2, F
             movlw   0                                       ; add carry
             addwfc  mul_16res+3, F
             movf    mul_16ptr2+1, W                 ;multiply upper byte
                                                     ;of num1 and lower
             mulwf   mul_16ptr1, W           ; byte of num2
             movf    PRODL, W                        ;add the result to mul_16res
             addwf   mul_16res+1, F          ;...
             movf    PRODH, W                        ;...
             addwfc  mul_16res+2, F          ;...
             movlw   0                                       ; add carry
             addwfc  mul_16res+3, F
             return

То, как я написал это прямо сейчас, заключается в том, что он умножает числа, хранящиеся в зарегистрированных, упомянутых в первом комментарии, и сохраняет их в 4 регистрах в комментарии. Это хорошо работает, если мне нужно сделать это умножение только один или два раза, т.е. я могу просто сказать что-то вроде:

mul_16ptr1   set    0x45
mul_16ptr2   set    0x47
mul_16res    set    0x50
call         mul_16bit

Чтобы умножить 0x45 и 0x47 и сохранить в 0x50. Проблема в том, что мне нужно вызвать это более одного раза для разных данных, потому что ассемблер не позволит мне дважды "установить" какой-либо из указателей. Я пытался использовать непрямой доступ (т.е. использовать LFSR1, LFSR2 и LFSR0 для хранения множимых и результата), но потом я просто попадаю в огромный беспорядок POSTINC0 и т. д. Можно ли как-то сделать эту функцию, вызывающую вещь, более приятной?


person Sean    schedule 18.06.2010    source источник


Ответы (3)


Функции в PIC18 обычно используют специальные входные переменные, такие как RegA, RegB и RegR. Итак, заявлены:

RegA res 2    ;16bit var
ResB res 2    ;16bit var
ResR res 4    ;32bit var

Вызов такой функции выглядит так:

;Constants declaration
    OperandA set 1234
    OperandB set 7777
;
;
;Prepare calling operand A   
    movlw low OperandA 
    movwf RegA 
    movlw high OperandA 
    movwf RegA + 1
;Prepare calling operand B         
    movlw low OperandB 
    movwf RegB + 0 
    movlw high OperandB 
    movwf RegB + 1
;Function call        
    call  MullAB_16bit
;Result is in RegR
person GJ.    schedule 19.06.2010

Да, язык ассемблера PIC делает многие вещи излишне сложными.

Я предполагаю, что вы делаете это как часть обучения, иначе вы бы использовали базовая библиотека математических функций, такая как Роджер Фроуд или Фр. Thomas McGahee, или, возможно, переключиться на язык более высокого уровня, где все вышеперечисленное можно заменить знаком «*» (BASIC, C, Pyastra, JAL, Forth и т. д.).

Соглашение о вызовах, которое демонстрирует GJ, чрезвычайно распространено, особенно в коде, перенесенном из PIC16, который имел только один регистр FSR и не имел регистров «PLUSW».

Поскольку PIC18 имеет регистры "PLUSWx", можно использовать множество более удобных соглашений о вызовах. Есть ли способ немного изменить это, чтобы получить "повторно входящий" код, который R. Риз рекомендует?

#include<18f4550>

OperandA res 2
OperandB res 2
Product res 4

clock_ticks res 2
useconds_per_clock_tick res 2
total_time res 4

    ; example of the "call" part of a possible 3-pointer calling convention.
    ; Public domain.
    ; To multiply by some number in Flash or EEPROM,
    ; first copy them (perhaps using TBLPTR/TABLAT)
    ; into some convenient temporary Operand buffer in RAM.
    ; Then:
    ; WARNING: untested code.
    ; put pointer to first (least-significant) byte of 16-bit operand A into FSR2
        BANKSEL FSR0
        lfsr2 OperandA 
    ; put pointer to first (least-significant) byte of 16-bit operand B into FSR1
        lfsr1 OperandB 
    ; put pointer to first (least-significant) byte of 32-bit product into FSR0
        lfsr0 Product
    ;Function call        
        call  mul16x16bit
    ;Result is in Product

    ; example of calling the same subroutine with different arguments.
        BANKSEL FSR0
        lfsr2 clock_ticks
        lfsr1 useconds_per_clock_tick
        lfsr0 total_time
        call mul16x16bit
    ; result is in total_time.
        return


    ;***********************************************************************
    ; mull16x16bit: subroutine that multiplies two 16 bit numbers
    ;    pointed to by the pointer FSR2, FSR2+1, FSR3, FSR3+1, and
    ;    returns the 32-bit result in addresses pointed to by
    ;    FSR0 to FSR0+3.
    ;***********************************************************************
    ; example of a function using a possible 3-pointer calling convention
    ; WARNING: untested code
    ; The pointers to operands are: FSR2, FSR1
    ; The pointer to the result is: FSR0.
    ; Mostly identical to code in the Microchip PIC18F2550 datasheet, page 98
    ; Public domain.

RESULT res 4 // temporary 4 byte register
TEMP EQU RESULT // temporary 1 byte register

mul_16bit:
         movlw   1                       ; multiply upper bytes
         movff   PLUSW2, TEMP
         movf    PLUSW1, W
         mulwf   TEMP
         movff   PRODH, RESULT+3
         movff   PRODL, RESULT+2

         movf    INDF2, W             ;multiply the lower bytes
         mulwf   INDF1, W
         movff   PRODH, RESULT+1
         movff   PRODL, RESULT+0

         movlw   1                   ; multiply the high byte of num2
         movf    PLUSW2
         mulwf   INDF1               ; and the low byte of num1
         movf    PRODL, W
         addwf   RESULT+1, F
         movf    PRODH, W
         addwfc  RESULT+2, F
         movlw   0                                       ; add carry
         addwfc  RESULT+3, F

         movlw   1                   ; multiply the high byte of num1
         movf    PLUSW1
         mulwf   INDF2               ; and the low byte of num2
         movf    PRODL, W
         addwf   RESULT+1, F
         movf    PRODH, W
         addwfc  RESULT+2, F
         movlw   0                                       ; add carry
         addwfc  RESULT+3, F

         movff   RESULT+0, POSTINC0   ; copy result to destination where FSR points.
         movff   RESULT+1, POSTINC0
         movff   RESULT+2, POSTINC0
         movff   RESULT+3, POSTINC0

         movlw   4
         subwf   FSR0  ; restore original value of FSR0.

         return
person Community    schedule 24.06.2010
comment
Что ж, многие из них необходимы, если вы хотите, чтобы чип оставался дешевым. - person BlueRaja - Danny Pflughoeft; 19.08.2010

Можете ли вы организовать вещи так, чтобы они вели себя разумно с FSR0-FSR2, указывающими на ваши регистры операнда и результата? НАПРИМЕР.

  movf   POSTINC0,w,c
  mulwf  POSTINC1,c     ; Op0L*Op1L (now both point at MSB)
  movff  PRODL,POSTINC2 ; Result0
  movff  PRODH,INDF2    ; Result1
  mulwf  POSTDEC1,c     ; Op0L*Op1H (now 0 points at MSB 1 at LSB)
  movf   PRODL,w,c
  addwf  POSTINC2,f,c   ; Result1 (now points at Result2)
  movlw  0
  addwfc PRODH,w,c
  movwf  POSTDEC2,c     ; Result2 (now points at Result1)
  movf   INDF0,w,c      ; Op0H
  mulwf  POSTINC1,c     ; Op1L
  movf   PRODL,w,c
  addwf  POSTINC2,f,c   ; Result1
  movf   PRODH,w,c
  addwfc POSTINC2,f,c   ; Result2 (carry may be outstanding)
  clrf   INDF2,f,c      ; Result3
  rlcf   POSTDEC2,f,c   ; Store carry
  movf   INDF0,w,c      ; Op0H
  mulwf  POSTINC1,c     ; Op1H
  movf   PRODL,w,c
  addwf  POSTINC2,f,c
  movf   PRODH,w,c
  addwfc INDF2,f,c

LFSR дешевле, чем ручное перемещение больших объемов данных.

person supercat    schedule 19.08.2010