Pristine Ack-5.5
[Ack-5.5.git] / mach / z80 / int / dvu4.s
1 .define .dvu4
2 .sect .text
3 .sect .rom
4 .sect .data
5 .sect .bss
6 .sect .text
7
8 ! 4-byte divide routine for z80
9 ! parameters:
10 !    stack: divisor
11 !           dividend
12 !    stack: quotient (out)
13 !    bc de: remainder (out)  (high part in bc)
14
15
16
17 ! a n-byte divide may be implemented
18 ! using 2 (virtual) registers:
19 !  - a n-byte register containing
20 !    the divisor
21 !  - a 2n-byte shiftregister (VSR)
22 !
23 ! Initially, the VSR contains the dividend
24 ! in its low (right) n bytes and zeroes in its
25 ! high n bytes. The dividend is shifted
26 ! left into a "window" bit by bit. After
27 ! each shift, the contents of the window
28 ! is compared with the divisor. If it is
29 ! higher or equal, the divisor is subtracted from
30 ! it and a "1" bit is inserted in the
31 ! VSR from the right side; else a "0" bit
32 ! is inserted. These bits are shifted left
33 ! too during subsequent iterations.
34 ! At the end, the rightmost part of VSR
35 ! contains the quotient.
36 ! For n=4, we need 2*4+4 = 12 bytes of
37 ! registers. Unfortunately we only have
38 ! 5 2-byte registers on the z80
39 ! (bc,de,hl,ix and iy). Therefore we use
40 ! an overlay technique for the rightmost
41 ! 4 bytes of the VSR. The 32 iterations
42 ! are split up into two groups: during
43 ! the first 16 iterations we use the high
44 ! order 16 bits of the dividend; during
45 ! the last 16 iterations we use the
46 ! low order 16 bits.
47 ! register allocation:
48 !   VSR        iy hl ix
49 !   divisor   -de bc
50 .dvu4:
51         ! initialization
52         pop hl          ! save return address
53         ld (.retaddr),hl
54         pop bc          ! low part (2 bytes)
55                         ! of divisor in bc
56         xor a           ! clear carry, a := 0
57         ld h,a          ! hl := 0
58         ld l,a
59         ld (.flag),a    ! first pass main loop
60         pop de          ! high part divisor
61         sbc hl,de       ! inverse of high part
62         ex de,hl        ! of divisor in de
63         pop hl          ! save low part of
64                         ! dividend in memory
65         ld (.low),hl    ! used during second
66                         ! iteration over main loop
67         pop ix          ! high part of dividend
68         push iy         ! save LB
69         ld h,a          ! hl := 0
70         ld l,a
71         ld iy,0         ! now the VSR is initialized
72
73         ! main loop, done twice
74 1:
75         ld a,16
76         ! sub-loop, done 16 times
77 2:
78         add iy,iy       ! shift VSR left
79         add ix,ix
80         adc hl,hl
81         jp nc,3f
82         inc iy
83 3:
84         or a            ! subtract divisor from
85                         ! window (iy hl)
86         ld (.iysave),iy
87         sbc hl,bc
88         jr nc,4f        ! decrement iy if there
89                         ! was no borrow
90         dec iy
91 4:
92         add iy,de       ! there is no "sbc iy,ss"
93                         ! on the z80, so de was
94                         ! inverted during init.
95         inc ix
96         ! see if the result is non-negative,
97         ! otherwise undo the subtract.
98         ! note that this uncooperating machine
99         ! does not set its S -or Z flag after
100         ! a 16-bit add.
101         ex (sp),iy      ! does anyone see a better
102         ex (sp),hl      ! solution ???
103         bit 7,h
104         ex (sp),hl
105         ex (sp),iy
106         jp z,5f
107         ! undo the subtract
108         add hl,bc
109         ld iy,(.iysave)
110         dec ix
111 5:
112         dec a
113         jr nz,2b
114         ld a,(.flag)    ! see if this was first or
115                         ! second iteration of main loop
116         or a            ! 0=first, 1=second
117         jr nz,6f
118         inc a           ! a := 1
119         ld (.flag),a    ! flag := 1
120         ld (.result),ix ! save high part of result
121         ld ix,(.low)    ! initialize second
122                         ! iteration, ix := low
123                         ! part of dividend
124         jr 1b
125 6:
126         ! clean up
127         push iy         ! transfer remainder
128         pop bc          ! from iy-hl to bc-de
129         ex de,hl
130         pop iy          ! restore LB
131         ld hl,(.result) ! high part of result
132         push hl
133         push ix         ! low part of result
134         ld hl,(.retaddr)
135         jp (hl)         ! return
136
137 .sect .data
138 .flag:          .data1 0
139 .low:           .data2 0
140 .iysave:        .data2 0
141 .retaddr:       .data2 0
142 .result:        .data2 0