Computer Design

University of Cambridge Computer Laboratory

Divide Code Example for Lecture 4

At the end of lecture 2 a code example was given to perform integer division. Below is a copy of the assembler routine, a simple C test routine with a similar divide routine also witten in C, and the assembler output from compiling this code.


Assembler Routine

; divide function written in ARM assembler
; signature: int divasm(int a, int b);

        AREA |C$$code|, CODE, READONLY
|x$codeseg|

        EXPORT  divasm
divasm                          ; enters with a and b in registers a1 and a2
        MOV     a3,#1           ; a3=Rcnt from lecture
divasm1
        CMP     a2,#0x80000000  ; shift a2 left until top bit set
        CMPCC   a2,a1           ; ...or a2>a1
        MOVCC   a2,a2,ASL#1     ; shift a2 left if required
        MOVCC   a3,a3,ASL#1     ; shift a3 left if required
        BCC     divasm1         ; repeat whilst more shifting required
        MOV     ip,#0           ; ip used to store result
divasm2
        CMP     a1,a2           ; test for possible subtraction
        SUBCS   a1,a1,a2        ; subtract if a1>a2
        ADDCS   ip,ip,a3        ; put relivant bit into result
        MOVS    a3,a3,LSR#1     ; shift control bit
        MOVNE   a2,a2,LSR#1     ; halve unless finished
        BNE     divasm2         ; loop if there is more to do

        MOV     a1,ip           ; return result in register a1
        MOV     pc,lr           ; return from the subroutine

|x$dataseg|

        END

C  Test Code and Divide Routine

#include 

/* Simple test program for divasm.s and a C equivalent                  */
/* compile using 'armcc -li testdiv.c divasm.s                          */
/*                                                          Simon Moore */


extern int divasm(int a, int b);


int divc(int a,int b)
{
  int r;
  int t=1;

  while( (b&0x40000000) == 0 ) {  /* fails if b=0 */
    b=b<<1;
    t=t<<1;
  }

  r=0;
  do {
    if((a-b)>=0) {
      a=a-b;
      r=r+t;
    }
    b=b>>1;
    t=t>>1;
  } while(t!=0);
  return r;
}



int main( int argc, char **argv )
{
  int i,j,k;
  for(i=1; i<64; i+=3) {
    j=divasm(1234,i);
    k=divc(1234,i);
    printf("1234/%2d = %4d %s",i,j,(1234/i)==j ? "....correct" : "ERROR!!!   ");
    printf(" = %4d %s\n",k,(1234/i)==k ? "....correct" : "ERROR!!!   ");
  }
  return 0;
}

Disassembled Output From Compling the C Routine

; generated by Norcroft  ARM C vsn 4.62 (Advanced RISC Machines) [May 04 1994]

        AREA |C$$code|, CODE, READONLY
|x$codeseg|

        EXPORT  divc
divc
        MOV      a3,#1
        TST      a2,#&40000000
        BNE      |L00001c.J5.divc|
|L00000c.J4.divc|
        MOV      a2,a2,LSL #1
        MOV      a3,a3,LSL #1
        TST      a2,#&40000000
        BEQ      |L00000c.J4.divc|
|L00001c.J5.divc|
        MOV      a4,#0
|L000020.J8.divc|
        SUBS     ip,a1,a2
        MOVPL    a1,ip
        ADDPL    a4,a4,a3
        MOV      a2,a2,ASR #1
        MOVS     a3,a3,ASR #1
        BNE      |L000020.J8.divc|
        MOV      a1,a4
        MOV      pc,lr

        IMPORT  __rt_stkovf_split_small
        IMPORT  divasm
        IMPORT  __rt_sdiv
        IMPORT  _printf
        EXPORT  main
main
        MOV      ip,sp
        STMDB    sp!,{v1-v4,fp,ip,lr,pc}
        SUB      fp,ip,#4
        CMP      sp,sl
        BLLT     __rt_stkovf_split_small
        MOV      v2,#1
|L000058.J4.main|
        MOV      a2,v2
        MOV      a1,#&d2
        ADD      a1,a1,#&400
        BL       divasm
        MOV      v4,a1
        MOV      a2,v2
        MOV      a1,#&d2
        ADD      a1,a1,#&400
        BL       divc
        MOV      v3,a1
        MOV      a1,v2
        MOV      a2,#&d2
        ADD      a2,a2,#&400
        BL       __rt_sdiv
        MOV      v1,a1
        TEQ      a1,v4
        ADDNE    a4,pc,#L0000dc-.-8
        ADDEQ    a4,pc,#L0000e8-.-8
        MOV      a3,v4
        MOV      a2,v2
        ADD      a1,pc,#L0000f4-.-8
        BL       _printf
        TEQ      v1,v3
        ADDNE    a3,pc,#L0000dc-.-8
        ADDEQ    a3,pc,#L0000e8-.-8
        MOV      a2,v3
        ADD      a1,pc,#L000108-.-8
        BL       _printf
        ADD      v2,v2,#3
        CMP      v2,#&40
        BLT      |L000058.J4.main|
        MOV      a1,#0
        LDMDB    fp,{v1-v4,fp,sp,pc}
L0000dc
        DCB     &45,&52,&52,&4f
        DCB     &52,&21,&21,&21
        DCB     &20,&20,&20,&00
L0000e8
        DCB     &2e,&2e,&2e,&2e
        DCB     &63,&6f,&72,&72
        DCB     &65,&63,&74,&00
L0000f4
        DCB     &31,&32,&33,&34
        DCB     &2f,&25,&32,&64
        DCB     &20,&3d,&20,&25
        DCB     &34,&64,&20,&25
        DCB     &73,&00,&00,&00
L000108
        DCB     &20,&3d,&20,&25
        DCB     &34,&64,&20,&25
        DCB     &73,&0a,&00,&00

        AREA |C$$data|,DATA

|x$dataseg|

        END

Back to the main index