2
\$\begingroup\$

I'm currently using MPLABX IDE to develop for a PIC16F877A microcontroller. I want to divide two numbers and find out the quotient (let the two numbers be 10 and 4) and store in a register.

I was thinking of a loop which increments the value of register by 1 every time 4 goes in 10 until it becomes zero or indivisible (as in integer).

I'm not able to figure out a way to make the controller recognize the end of division when either reminder is zero, negative or less than divisor.

I would appreciate any suggestions for accomplishing this using Assembly language.

\$\endgroup\$
7
  • 3
    \$\begingroup\$ Welcome to EE.SE! This appears to be a homework question. As such, you need to show us your work so far, and explain which part of the question you're having trouble with. For future reference: Homework questions on EE.SE enjoy/suffer a special treatment. We don't provide complete answers, we only provide hints or Socratic questions, and only when you have demonstrated sufficient effort of your own. Otherwise, we would be doing you a disservice, and getting swamped by homework questions at the same time. See also here. \$\endgroup\$
    – Dave Tweed
    Commented Oct 22, 2019 at 12:58
  • 1
    \$\begingroup\$ Hint: Assuming the divisor is positive (and not zero), if the remainder is not less than the divisor, then you're not done yet. In other words, one test covers all three cases. \$\endgroup\$
    – Dave Tweed
    Commented Oct 22, 2019 at 13:01
  • 2
    \$\begingroup\$ For speed, look up not-restoring division algorithms. These can produce both quotient and remainder or just the quotient (rounded or truncated.) If speed isn't important, there are several options, all of them easy to look up. Also, PIC library code for their C compilers is free to look up and provides assembly code, as well. Lots of options. \$\endgroup\$
    – jonk
    Commented Oct 22, 2019 at 13:24
  • \$\begingroup\$ After each time you've subtracted 4 from 10 check the carry flag. If the carry flag is 0 then the numerator has gone negative at which point you would subtract 1 from the count value and add 4 back into the numerator to give the remainder. \$\endgroup\$
    – user173271
    Commented Oct 22, 2019 at 13:31
  • 3
    \$\begingroup\$ If not a homework question and speed (nor accuracy) is important, research which math libraries are available and the IEEE (vs. Microchip) floating-point format. It is possible to use floating-point math directly in PIC assembler. \$\endgroup\$
    – rdtsc
    Commented Oct 22, 2019 at 14:05

3 Answers 3

0
\$\begingroup\$

This is another way:

;   
; File: main.asm
; Target: PIC16F877A
; IDE: MPLABX v5.25
; Assembler: MPASM v5.84
;   
; Description:
;
;   Show implementation and test of integer division.
;   
;
; Notes:
;
;   Forum post: https://electronics.stackexchange.com/questions/463950/how-do-i-perform-division-of-two-numbers-in-pic16f877a-in-assembly-language
;
;
    list    r=dec,n=0,c=132
    errorlevel -302, -312
;
#include "p16F877A.inc"

     __CONFIG _FOSC_XT & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF

#define FOSC (4000000)
#define FCYC (FOSC/4)
;
; Define macros to help
; with bank selection
;
#define BANK0  (h'000')
#define BANK1  (h'080')
#define BANK2  (h'100')
#define BANK3  (h'180')
;
;**********************************************************************
RESET_VECTOR code 0x000         ; processor reset vector
    nop 
    goto    start               ; begin PIC initialization

;------------------------------------------------------------------------
start:
    clrf    INTCON              ; Disable all interrupt sources
    clrf    TMR0
    banksel BANK1
    clrf    PIE1
    clrf    PIE2

    movlw   b'11000000'         ; Pull-ups off, INT edge low to high, WDT prescale 1:1 
    movwf   OPTION_REG          ; TMR0 clock edge low to high, TMR0 clock = FCY, TMR0 prescale 1:2

    movlw   b'11111111'         ; 
    movwf   TRISA           

    movlw   b'01111111'         ; 
    movwf   TRISB           

    movlw   b'11111111'         ; 
    movwf   TRISC           

    movlw   b'11111111'         ; 
    movwf   TRISD

    ; disable comparators
    movlw   b'00000111'
    movwf   CMCON

    ; Set all ADC inputs for digital I/O
    movlw   b'00000110'
    movwf   ADCON1

    banksel BANK0
    pagesel main
    goto    main
;
; Interger 8x8 division with remainder
;
;   Quotient = Dividen / Divisor, with Remainder
;
; Input:    Dividen 
;       Divisor
;
; Output:   Quotient in WREG 
;       Remainder
;
Div8x8_DATA udata   0x20
Divisor     res     1
Dividen 
Quotient    res     1
Remainder   res     1
BitCount    res     1

Div8x8_CODE code
Div8x8:
    banksel BitCount
    movlw   8
    movwf   BitCount
    clrf    Remainder
Div8x8Loop:
    clrc
    rlf     Dividen,F
    rlf     Remainder,F
    movf    Divisor,W
    subwf   Remainder,W
    skpnz
    goto    BigEnough
    skpc
    goto    TooSmall
BigEnough:
    movwf   Remainder
    bsf     Dividen,0
TooSmall:
    decfsz  BitCount,F
    goto    Div8x8Loop
    movf    Quotient,W
    return
;
; Main application loop
;
MAIN_DATA   udata
Value1      res     1
Value2      res     1

MAIN_CODE code
main:
;
; Loop here forever testing Dividen and Divisors
;
ProcessLoop:
;   
;
    banksel Value1
    clrf    Value1
    decf    Value1,F

    clrf    Value2
    decf    Value2,F

TestLoop:
    banksel Value1
    movf    Value1,W
    banksel Divisor
    movwf   Divisor

    banksel Value2
    movf    Value2,W
    banksel Dividen
    movwf   Dividen

    call    Div8x8

    banksel Value1
    decfsz  Value1,F
    goto    TestLoop
    decf    Value1,F

    banksel Value2
    decfsz  Value2,F
    goto    TestLoop
    decf    Value2,F

    goto    ProcessLoop

    end

If you are going to crib this for you homework at least you can add the comments.

\$\endgroup\$
0
\$\begingroup\$

@dan1138 was right this is the code for the pic18f45k22

Division_lOOP

    movwf   NUMERATOR   ;numerator is set by working register before entering the loop
    movlw   15
    movwf   DENOMINATOR
    movlw   8
    movwf   BitCount
    clrf    Remainder
Div8x8Loop:
    bcf STATUS,C
    RLCF    NUMERATOR,F     ;Rotates left if  carry
    RLCF    Remainder,F     ;Rotates left if carry
    movf    DENOMINATOR,W       ;moves lateral to working register
    subwf   Remainder,W     ; Subtracts remainder from working register
    BTFSC   STATUS,C        ;tests if carry has been set
    goto    BigEnough
    btfss   STATUS,C         ;tests if carry has not been set
    goto    TooSmall
BigEnough:
    movwf   Remainder       ;moves working register to remainder
    bsf     NUMERATOR,0     ;sets Numbator bit
    
    
TooSmall:
    
    decfsz  BitCount,F      ; decreases bit count
    goto    Div8x8Loop      
    movf    NUMERATOR,W      ;answer
    return
\$\endgroup\$
0
\$\begingroup\$

A very simple pseudo-code algorithm:
suppose you have to calculate X/Y = Q, to find Q :

      q = 0
      loop:
            q++
            x = q * Y
            if x == X
                  Q = q
                  break
            else if x > X                   goto loop
                  Q = q - 1
                  break
            else
               goto loop

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.