123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- .define .dvu4
- .sect .text
- .sect .rom
- .sect .data
- .sect .bss
- .sect .text
- ! 4-byte divide routine for z80
- ! parameters:
- ! stack: divisor
- ! dividend
- ! stack: quotient (out)
- ! bc de: remainder (out) (high part in bc)
- ! a n-byte divide may be implemented
- ! using 2 (virtual) registers:
- ! - a n-byte register containing
- ! the divisor
- ! - a 2n-byte shiftregister (VSR)
- !
- ! Initially, the VSR contains the dividend
- ! in its low (right) n bytes and zeroes in its
- ! high n bytes. The dividend is shifted
- ! left into a "window" bit by bit. After
- ! each shift, the contents of the window
- ! is compared with the divisor. If it is
- ! higher or equal, the divisor is subtracted from
- ! it and a "1" bit is inserted in the
- ! VSR from the right side! else a "0" bit
- ! is inserted. These bits are shifted left
- ! too during subsequent iterations.
- ! At the end, the rightmost part of VSR
- ! contains the quotient.
- ! For n=4, we need 2*4+4 = 12 bytes of
- ! registers. Unfortunately we only have
- ! 5 2-byte registers on the z80
- ! (bc,de,hl,ix and iy). Therefore we use
- ! an overlay technique for the rightmost
- ! 4 bytes of the VSR. The 32 iterations
- ! are split up into two groups: during
- ! the first 16 iterations we use the high
- ! order 16 bits of the dividend! during
- ! the last 16 iterations we use the
- ! low order 16 bits.
- ! register allocation:
- ! VSR iy hl ix
- ! divisor -de bc
- .dvu4:
- ! initialization
- pop hl ! save return address
- ld (.retaddr),hl
- pop bc ! low part (2 bytes)
- ! of divisor in bc
- xor a ! clear carry, a := 0
- ld h,a ! hl := 0
- ld l,a
- ld (.flag),a ! first pass main loop
- pop de ! high part divisor
- sbc hl,de ! inverse of high part
- ex de,hl ! of divisor in de
- pop hl ! save low part of
- ! dividend in memory
- ld (.low),hl ! used during second
- ! iteration over main loop
- pop ix ! high part of dividend
- push iy ! save LB
- ld h,a ! hl := 0
- ld l,a
- ld iy,0 ! now the VSR is initialized
- ! main loop, done twice
- 1:
- ld a,16
- ! sub-loop, done 16 times
- 2:
- add iy,iy ! shift VSR left
- add ix,ix
- adc hl,hl
- jp nc,3f
- inc iy
- 3:
- or a ! subtract divisor from
- ! window (iy hl)
- ld (.iysave),iy
- sbc hl,bc
- jr nc,4f ! decrement iy if there
- ! was no borrow
- dec iy
- 4:
- add iy,de ! there is no "sbc iy,ss"
- ! on the z80, so de was
- ! inverted during init.
- inc ix
- ! see if the result is non-negative,
- ! otherwise undo the subtract.
- ! note that this uncooperating machine
- ! does not set its S -or Z flag after
- ! a 16-bit add.
- ex (sp),iy ! does anyone see a better
- ex (sp),hl ! solution ???
- bit 7,h
- ex (sp),hl
- ex (sp),iy
- jp z,5f
- ! undo the subtract
- add hl,bc
- ld iy,(.iysave)
- dec ix
- 5:
- dec a
- jr nz,2b
- ld a,(.flag) ! see if this was first or
- ! second iteration of main loop
- or a ! 0=first, 1=second
- jr nz,6f
- inc a ! a := 1
- ld (.flag),a ! flag := 1
- ld (.result),ix ! save high part of result
- ld ix,(.low) ! initialize second
- ! iteration, ix := low
- ! part of dividend
- jr 1b
- 6:
- ! clean up
- push iy ! transfer remainder
- pop bc ! from iy-hl to bc-de
- ex de,hl
- pop iy ! restore LB
- ld hl,(.result) ! high part of result
- push hl
- push ix ! low part of result
- ld hl,(.retaddr)
- jp (hl) ! return
- .sect .data
- .flag: .data1 0
- .low: .data2 0
- .iysave: .data2 0
- .retaddr: .data2 0
- .result: .data2 0
|