]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm
PciLib:
[mirror_edk2.git] / EdkModulePkg / Universal / Ebc / Dxe / Ia32 / Ia32Math.asm
1 TITLE Ia32math.asm: Generic math routines for EBC interpreter running on IA32 processor
2
3 ;------------------------------------------------------------------------------
4 ;
5 ; Copyright (c) 2006, Intel Corporation
6 ; All rights reserved. This program and the accompanying materials
7 ; are licensed and made available under the terms and conditions of the BSD License
8 ; which accompanies this distribution. The full text of the license may be found at
9 ; http://opensource.org/licenses/bsd-license.php
10 ;
11 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 ;
14 ; Module Name:
15 ;
16 ; Ia32math.asm
17 ;
18 ; Abstract:
19 ;
20 ; Generic math routines for EBC interpreter running on IA32 processor
21 ;
22 ;------------------------------------------------------------------------------
23
24 .686P
25 .XMM
26 .MODEL SMALL
27 .CODE
28
29 LeftShiftU64 PROTO C Operand: QWORD, CountIn: QWORD
30 RightShiftU64 PROTO C Operand: QWORD, CountIn: QWORD
31 ARightShift64 PROTO C Operand: QWORD, CountIn: QWORD
32 MulU64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
33 MulS64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
34 DivU64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD
35 DivS64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD
36
37
38 LeftShiftU64 PROC C Operand: QWORD, CountIn: QWORD
39
40 ;------------------------------------------------------------------------------
41 ; UINT64
42 ; LeftShiftU64 (
43 ; IN UINT64 Operand,
44 ; IN UINT64 CountIn
45 ; )
46 ;
47 ; Routine Description:
48 ;
49 ; Left-shift a 64-bit value.
50 ;
51 ; Arguments:
52 ;
53 ; Operand - the value to shift
54 ; Count - shift count
55 ;
56 ; Returns:
57 ;
58 ; Operand << Count
59 ;------------------------------------------------------------------------------
60
61 push ecx
62 ;
63 ; if (CountIn > 63) return 0;
64 ;
65 cmp dword ptr CountIn[4], 0
66 jne _LeftShiftU64_Overflow
67 mov ecx, dword ptr CountIn[0]
68 cmp ecx, 63
69 jbe _LeftShiftU64_Calc
70
71 _LeftShiftU64_Overflow:
72 xor eax, eax
73 xor edx, edx
74 jmp _LeftShiftU64_Done
75
76 _LeftShiftU64_Calc:
77 mov eax, dword ptr Operand[0]
78 mov edx, dword ptr Operand[4]
79
80 shld edx, eax, cl
81 shl eax, cl
82 cmp ecx, 32
83 jc short _LeftShiftU64_Done
84
85 mov edx, eax
86 xor eax, eax
87
88 _LeftShiftU64_Done:
89 pop ecx
90 ret
91
92 LeftShiftU64 ENDP
93
94
95 RightShiftU64 PROC C Operand: QWORD, CountIn: QWORD
96
97 ;------------------------------------------------------------------------------
98 ; UINT64
99 ; RightShiftU64 (
100 ; IN UINT64 Operand,
101 ; IN UINT64 CountIn
102 ; )
103 ;
104 ; Routine Description:
105 ;
106 ; Right-shift an unsigned 64-bit value.
107 ;
108 ; Arguments:
109 ;
110 ; Operand - the value to shift
111 ; Count - shift count
112 ;
113 ; Returns:
114 ;
115 ; Operand >> Count
116 ;------------------------------------------------------------------------------
117
118 push ecx
119 ;
120 ; if (CountIn > 63) return 0;
121 ;
122 cmp dword ptr CountIn[4], 0
123 jne _RightShiftU64_Overflow
124 mov ecx, dword ptr CountIn[0]
125 cmp ecx, 63
126 jbe _RightShiftU64_Calc
127
128 _RightShiftU64_Overflow:
129 xor eax, eax
130 xor edx, edx
131 jmp _RightShiftU64_Done
132
133 _RightShiftU64_Calc:
134 mov eax, dword ptr Operand[0]
135 mov edx, dword ptr Operand[4]
136
137 shrd eax, edx, cl
138 shr edx, cl
139 cmp ecx, 32
140 jc short _RightShiftU64_Done
141
142 mov eax, edx
143 xor edx, edx
144
145 _RightShiftU64_Done:
146 pop ecx
147 ret
148
149 RightShiftU64 ENDP
150
151
152 ARightShift64 PROC C Operand: QWORD, CountIn: QWORD
153
154 ;------------------------------------------------------------------------------
155 ; INT64
156 ; ARightShift64 (
157 ; IN INT64 Operand,
158 ; IN UINT64 CountIn
159 ; )
160 ;
161 ; Routine Description:
162 ;
163 ; Arithmatic shift a 64 bit signed value.
164 ;
165 ; Arguments:
166 ;
167 ; Operand - the value to shift
168 ; Count - shift count
169 ;
170 ; Returns:
171 ;
172 ; Operand >> Count
173 ;------------------------------------------------------------------------------
174
175 push ecx
176 ;
177 ; If they exceeded the max shift count, then return either 0 or all F's
178 ; depending on the sign bit.
179 ;
180 cmp dword ptr CountIn[4], 0
181 jne _ARightShiftU64_Overflow
182 mov ecx, dword ptr CountIn[0]
183 cmp ecx, 63
184 jbe _ARightShiftU64_Calc
185
186 _ARightShiftU64_Overflow:
187 ;
188 ; Check the sign bit of Operand
189 ;
190 bt dword ptr Operand[4], 31
191 jnc _ARightShiftU64_Return_Zero
192 ;
193 ; return -1
194 ;
195 or eax, 0FFFFFFFFh
196 or edx, 0FFFFFFFFh
197 jmp _ARightShiftU64_Done
198
199 _ARightShiftU64_Return_Zero:
200 xor eax, eax
201 xor edx, edx
202 jmp _ARightShiftU64_Done
203
204 _ARightShiftU64_Calc:
205 mov eax, dword ptr Operand[0]
206 mov edx, dword ptr Operand[4]
207
208 shrd eax, edx, cl
209 sar edx, cl
210 cmp ecx, 32
211 jc short _ARightShiftU64_Done
212
213 ;
214 ; if ecx >= 32, then eax = edx, and edx = sign bit
215 ;
216 mov eax, edx
217 sar edx, 31
218
219 _ARightShiftU64_Done:
220 pop ecx
221 ret
222
223 ARightShift64 ENDP
224
225
226 MulU64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
227
228 ;------------------------------------------------------------------------------
229 ; UINT64
230 ; MulU64x64 (
231 ; UINT64 Value1,
232 ; UINT64 Value2,
233 ; UINT64 *ResultHigh
234 ; )
235 ;
236 ; Routine Description:
237 ;
238 ; Multiply two unsigned 64-bit values.
239 ;
240 ; Arguments:
241 ;
242 ; Value1 - first value to multiply
243 ; Value2 - value to multiply by Value1
244 ; ResultHigh - result to flag overflows
245 ;
246 ; Returns:
247 ;
248 ; Value1 * Value2
249 ; The 128-bit result is the concatenation of *ResultHigh and the return value
250 ;------------------------------------------------------------------------------
251
252 push ebx
253 push ecx
254 mov ebx, ResultHigh ; ebx points to the high 4 words of result
255 ;
256 ; The result consists of four double-words.
257 ; Here we assume their names from low to high: dw0, dw1, dw2, dw3
258 ;
259 mov eax, dword ptr Value1[0]
260 mul dword ptr Value2[0]
261 push eax ; eax contains final result of dw0, push it
262 mov ecx, edx ; ecx contains partial result of dw1
263
264 mov eax, dword ptr Value1[4]
265 mul dword ptr Value2[0]
266 add ecx, eax ; add eax to partial result of dw1
267 adc edx, 0
268 mov dword ptr [ebx], edx ; lower double-word of ResultHigh contains partial result of dw2
269
270 mov eax, dword ptr Value1[0]
271 mul dword ptr Value2[4]
272 add ecx, eax ; add eax to partial result of dw1
273 push ecx ; ecx contains final result of dw1, push it
274 adc edx, 0
275 mov ecx, edx ; ecx contains partial result of dw2, together with ResultHigh
276
277 mov eax, dword ptr Value1[4]
278 mul dword ptr Value2[4]
279 add ecx, eax ; add eax to partial result of dw2
280 adc edx, 0
281 add dword ptr [ebx], ecx ; lower double-word of ResultHigh contains final result of dw2
282 adc edx, 0
283 mov dword ptr [ebx + 4], edx ; high double-word of ResultHigh contains final result of dw3
284
285 pop edx ; edx contains the final result of dw1
286 pop eax ; edx contains the final result of dw0
287 pop ecx
288 pop ebx
289 ret
290
291 MulU64x64 ENDP
292
293
294 MulS64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
295
296 ;------------------------------------------------------------------------------
297 ; INT64
298 ; MulS64x64 (
299 ; INT64 Value1,
300 ; INT64 Value2,
301 ; INT64 *ResultHigh
302 ; )
303 ;
304 ; Routine Description:
305 ;
306 ; Multiply two signed 64-bit values.
307 ;
308 ; Arguments:
309 ;
310 ; Value1 - first value to multiply
311 ; Value2 - value to multiply by Value1
312 ; ResultHigh - result to flag overflows
313 ;
314 ; Returns:
315 ;
316 ; Value1 * Value2
317 ; The 128-bit result is the concatenation of *ResultHigh and the return value
318 ;------------------------------------------------------------------------------
319
320 push ebx
321 push ecx
322 mov ebx, ResultHigh ; ebx points to the high 4 words of result
323 xor ecx, ecx ; the lowest bit of ecx flags the sign
324
325 mov edx, dword ptr Value1[4]
326 bt edx, 31
327 jnc short _MulS64x64_A_Positive
328 ;
329 ; a is negative
330 ;
331 mov eax, dword ptr Value1[0]
332 not edx
333 not eax
334 add eax, 1
335 adc edx, 0
336 mov dword ptr Value1[0], eax
337 mov dword ptr Value1[4], edx
338 btc ecx, 0
339
340 _MulS64x64_A_Positive:
341 mov edx, dword ptr Value2[4]
342 bt edx, 31
343 jnc short _MulS64x64_B_Positive
344 ;
345 ; b is negative
346 ;
347 mov eax, dword ptr Value2[0]
348 not edx
349 not eax
350 add eax, 1
351 adc edx, 0
352 mov dword ptr Value2[0], eax
353 mov dword ptr Value2[4], edx
354 btc ecx, 0
355
356 _MulS64x64_B_Positive:
357 invoke MulU64x64, Value1, Value2, ResultHigh
358 bt ecx, 0
359 jnc short _MulS64x64_Done
360 ;
361 ;negate the result
362 ;
363 not eax
364 not edx
365 not dword ptr [ebx]
366 not dword ptr [ebx + 4]
367 add eax, 1
368 adc edx, 0
369 adc dword ptr [ebx], 0
370 adc dword ptr [ebx + 4], 0
371
372 _MulS64x64_Done:
373 pop ecx
374 pop ebx
375 ret
376
377 MulS64x64 ENDP
378
379
380 DivU64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD,
381
382 ;------------------------------------------------------------------------------
383 ; UINT64
384 ; DivU64x64 (
385 ; IN UINT64 Dividend,
386 ; IN UINT64 Divisor,
387 ; OUT UINT64 *Remainder OPTIONAL,
388 ; OUT UINT32 *Error
389 ; )
390 ;
391 ; Routine Description:
392 ;
393 ; This routine allows a 64 bit value to be divided with a 64 bit value returns
394 ; 64bit result and the Remainder
395 ;
396 ; Arguments:
397 ;
398 ; Dividend - dividend
399 ; Divisor - divisor
400 ; ResultHigh - result to flag overflows
401 ; Error - flag for error
402 ;
403 ; Returns:
404 ;
405 ; Dividend / Divisor
406 ; Remainder = Dividend mod Divisor
407 ;------------------------------------------------------------------------------
408
409 push ecx
410
411 mov eax, Error
412 mov dword ptr [eax], 0
413
414 cmp dword ptr Divisor[0], 0
415 jne _DivU64x64_Valid
416 cmp dword ptr Divisor[4], 0
417 jne _DivU64x64_Valid
418 ;
419 ; the divisor is zero
420 ;
421 mov dword ptr [eax], 1
422 cmp Remainder, 0
423 je _DivU64x64_Invalid_Return
424 ;
425 ; fill the remainder if the pointer is not null
426 ;
427 mov eax, Remainder
428 mov dword ptr [eax], 0
429 mov dword ptr [eax + 4], 80000000h
430
431 _DivU64x64_Invalid_Return:
432 xor eax, eax
433 mov edx, 80000000h
434 jmp _DivU64x64_Done
435
436 _DivU64x64_Valid:
437 ;
438 ; let edx and eax contain the intermediate result of remainder
439 ;
440 xor edx, edx
441 xor eax, eax
442 mov ecx, 64
443
444 _DivU64x64_Wend:
445 ;
446 ; shift dividend left one
447 ;
448 shl dword ptr Dividend[0], 1
449 rcl dword ptr Dividend[4], 1
450 ;
451 ; rotate intermediate result of remainder left one
452 ;
453 rcl eax, 1
454 rcl edx, 1
455
456 cmp edx, dword ptr Divisor[4]
457 ja _DivU64x64_Sub_Divisor
458 jb _DivU64x64_Cont
459 cmp eax, dword ptr Divisor[0]
460 jb _DivU64x64_Cont
461
462 _DivU64x64_Sub_Divisor:
463 ;
464 ; If intermediate result of remainder is larger than
465 ; or equal to divisor, then set the lowest bit of dividend,
466 ; and subtract divisor from intermediate remainder
467 ;
468 bts dword ptr Dividend[0], 0
469 sub eax, dword ptr Divisor[0]
470 sbb edx, dword ptr Divisor[4]
471
472 _DivU64x64_Cont:
473 loop _DivU64x64_Wend
474
475 cmp Remainder, 0
476 je _DivU64x64_Assign
477 mov ecx, Remainder
478 mov dword ptr [ecx], eax
479 mov dword ptr [ecx + 4], edx
480
481 _DivU64x64_Assign:
482 mov eax, dword ptr Dividend[0]
483 mov edx, dword ptr Dividend[4]
484
485 _DivU64x64_Done:
486 pop ecx
487 ret
488
489 DivU64x64 ENDP
490
491 DivS64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD,
492
493 ;------------------------------------------------------------------------------
494 ; INT64
495 ; DivU64x64 (
496 ; IN INT64 Dividend,
497 ; IN INT64 Divisor,
498 ; OUT UINT64 *Remainder OPTIONAL,
499 ; OUT UINT32 *Error
500 ; )
501 ;
502 ; Routine Description:
503 ;
504 ; This routine allows a 64 bit signed value to be divided with a 64 bit
505 ; signed value returns 64bit result and the Remainder.
506 ;
507 ; Arguments:
508 ;
509 ; Dividend - dividend
510 ; Divisor - divisor
511 ; ResultHigh - result to flag overflows
512 ; Error - flag for error
513 ;
514 ; Returns:
515 ;
516 ; Dividend / Divisor
517 ; Remainder = Dividend mod Divisor
518 ;------------------------------------------------------------------------------
519
520 push ecx
521
522 mov eax, Error
523 mov dword ptr [eax], 0
524
525 cmp dword ptr Divisor[0], 0
526 jne _DivS64x64_Valid
527 cmp dword ptr Divisor[4], 0
528 jne _DivS64x64_Valid
529 ;
530 ; the divisor is zero
531 ;
532 mov dword ptr [eax], 1
533 cmp Remainder, 0
534 je _DivS64x64_Invalid_Return
535 ;
536 ; fill the remainder if the pointer is not null
537 ;
538 mov eax, Remainder
539 mov dword ptr [eax], 0
540 mov dword ptr [eax + 4], 80000000h
541
542 _DivS64x64_Invalid_Return:
543 xor eax, eax
544 mov edx, 80000000h
545 jmp _DivS64x64_Done
546
547 _DivS64x64_Valid:
548 ;
549 ; The lowest bit of ecx flags the sign of quotient,
550 ; The seconde lowest bit flags the sign of remainder
551 ;
552 xor ecx, ecx
553
554 mov edx, dword ptr Dividend[4]
555 bt edx, 31
556 jnc short _DivS64x64_Dividend_Positive
557 ;
558 ; dividend is negative
559 ;
560 mov eax, dword ptr Dividend[0]
561 not edx
562 not eax
563 add eax, 1
564 adc edx, 0
565 mov dword ptr Dividend[0], eax
566 mov dword ptr Dividend[4], edx
567 ;
568 ; set both the flags for signs of quotient and remainder
569 ;
570 btc ecx, 0
571 btc ecx, 1
572
573 _DivS64x64_Dividend_Positive:
574 mov edx, dword ptr Divisor[4]
575 bt edx, 31
576 jnc short _DivS64x64_Divisor_Positive
577 ;
578 ; divisor is negative
579 ;
580 mov eax, dword ptr Divisor[0]
581 not edx
582 not eax
583 add eax, 1
584 adc edx, 0
585 mov dword ptr Divisor[0], eax
586 mov dword ptr Divisor[4], edx
587 ;
588 ; just complement the flag for sign of quotient
589 ;
590 btc ecx, 0
591
592 _DivS64x64_Divisor_Positive:
593 invoke DivU64x64, Dividend, Divisor, Remainder, Error
594 bt ecx, 0
595 jnc short _DivS64x64_Remainder
596 ;
597 ; negate the quotient
598 ;
599 not eax
600 not edx
601 add eax, 1
602 adc edx, 0
603
604 _DivS64x64_Remainder:
605 bt ecx, 1
606 jnc short _DivS64x64_Done
607 ;
608 ; negate the remainder
609 ;
610 mov ecx, remainder
611 not dword ptr [ecx]
612 not dword ptr [ecx + 4]
613 add dword ptr [ecx], 1
614 adc dword ptr [ecx + 4], 0
615
616 _DivS64x64_Done:
617 pop ecx
618 ret
619
620 DivS64x64 ENDP
621
622 END