1 2-- Copyright (C) 1996 Morgan Kaufmann Publishers, Inc 3 4-- This file is part of VESTs (Vhdl tESTs). 5 6-- VESTs is free software; you can redistribute it and/or modify it 7-- under the terms of the GNU General Public License as published by the 8-- Free Software Foundation; either version 2 of the License, or (at 9-- your option) any later version. 10 11-- VESTs is distributed in the hope that it will be useful, but WITHOUT 12-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13-- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14-- for more details. 15 16-- You should have received a copy of the GNU General Public License 17-- along with VESTs; if not, write to the Free Software Foundation, 18-- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 20-- --------------------------------------------------------------------- 21-- 22-- $Id: bv_arithmetic_body.vhd,v 1.3 2001-10-26 16:29:33 paw Exp $ 23-- $Revision: 1.3 $ 24-- 25-- --------------------------------------------------------------------- 26 27package body bv_arithmetic is 28 29 ---------------------------------------------------------------- 30 -- Type conversions 31 ---------------------------------------------------------------- 32 33 function bv_to_natural ( bv : in bit_vector ) return natural is 34 35 variable result : natural := 0; 36 37 begin 38 for index in bv'range loop 39 result := result * 2 + bit'pos( bv(index) ); 40 end loop; 41 return result; 42 end function bv_to_natural; 43 44 function natural_to_bv ( nat : in natural; 45 length : in natural ) return bit_vector is 46 47 variable temp : natural := nat; 48 variable result : bit_vector(length - 1 downto 0) := (others => '0'); 49 50 begin 51 for index in result'reverse_range loop 52 result(index) := bit'val( temp rem 2 ); 53 temp := temp / 2; 54 exit when temp = 0; 55 end loop; 56 return result; 57 end function natural_to_bv; 58 59 function bv_to_integer ( bv : in bit_vector ) return integer is 60 61 variable temp : bit_vector(bv'range); 62 variable result : integer := 0; 63 64 begin 65 if bv(bv'left) = '1' then -- negative number 66 temp := not bv; 67 else 68 temp := bv; 69 end if; 70 for index in bv'range loop -- sign bit of temp = '0' 71 result := result * 2 + bit'pos( temp(index) ); 72 end loop; 73 if bv(bv'left) = '1' then 74 result := (-result) - 1; 75 end if; 76 return result; 77 end function bv_to_integer; 78 79 function integer_to_bv ( int : in integer; 80 length : in natural ) return bit_vector is 81 82 variable temp : integer; 83 variable result : bit_vector(length - 1 downto 0) := (others => '0'); 84 85 begin 86 if int < 0 then 87 temp := - (int + 1); 88 else 89 temp := int; 90 end if; 91 for index in result'reverse_range loop 92 result(index) := bit'val( temp rem 2 ); 93 temp := temp / 2; 94 exit when temp = 0; 95 end loop; 96 if int < 0 then 97 result := not result; 98 result(result'left) := '1'; 99 end if; 100 return result; 101 end function integer_to_bv; 102 103 ---------------------------------------------------------------- 104 -- Arithmetic operations 105 ---------------------------------------------------------------- 106 107 procedure bv_add ( bv1, bv2 : in bit_vector; 108 bv_result : out bit_vector; 109 overflow : out boolean ) is 110 111 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 112 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 113 variable result : bit_vector(bv_result'length - 1 downto 0); 114 variable carry_in : bit; 115 variable carry_out : bit := '0'; 116 117 begin 118 if bv1'length /= bv2'length or bv1'length /= bv_result'length then 119 report "bv_add: operands of different lengths" 120 severity failure; 121 else 122 for index in result'reverse_range loop 123 carry_in := carry_out; -- of previous bit 124 result(index) := op1(index) xor op2(index) xor carry_in; 125 carry_out := (op1(index) and op2(index)) 126 or (carry_in and (op1(index) xor op2(index))); 127 end loop; 128 bv_result := result; 129 overflow := carry_out /= carry_in; 130 end if; 131 end procedure bv_add; 132 133 function "+" ( bv1, bv2 : in bit_vector ) return bit_vector is 134 135 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 136 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 137 variable result : bit_vector(bv1'length - 1 downto 0); 138 variable carry_in : bit; 139 variable carry_out : bit := '0'; 140 141 begin 142 if bv1'length /= bv2'length then 143 report """+"": operands of different lengths" 144 severity failure; 145 else 146 for index in result'reverse_range loop 147 carry_in := carry_out; -- of previous bit 148 result(index) := op1(index) xor op2(index) xor carry_in; 149 carry_out := (op1(index) and op2(index)) 150 or (carry_in and (op1(index) xor op2(index))); 151 end loop; 152 end if; 153 return result; 154 end function "+"; 155 156 procedure bv_sub ( bv1, bv2 : in bit_vector; 157 bv_result : out bit_vector; 158 overflow : out boolean ) is 159 160 -- subtraction implemented by adding ((not bv2) + 1), ie -bv2 161 162 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 163 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 164 variable result : bit_vector(bv_result'length - 1 downto 0); 165 variable carry_in : bit; 166 variable carry_out : bit := '1'; 167 168 begin 169 if bv1'length /= bv2'length or bv1'length /= bv_result'length then 170 report "bv_sub: operands of different lengths" 171 severity failure; 172 else 173 for index in result'reverse_range loop 174 carry_in := carry_out; -- of previous bit 175 result(index) := op1(index) xor (not op2(index)) xor carry_in; 176 carry_out := (op1(index) and (not op2(index))) 177 or (carry_in and (op1(index) xor (not op2(index)))); 178 end loop; 179 bv_result := result; 180 overflow := carry_out /= carry_in; 181 end if; 182 end procedure bv_sub; 183 184 function "-" ( bv1, bv2 : in bit_vector ) return bit_vector is 185 186 -- subtraction implemented by adding ((not bv2) + 1), ie -bv2 187 188 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 189 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 190 variable result : bit_vector(bv1'length - 1 downto 0); 191 variable carry_in : bit; 192 variable carry_out : bit := '1'; 193 194 begin 195 if bv1'length /= bv2'length then 196 report """-"": operands of different lengths" 197 severity failure; 198 else 199 for index in result'reverse_range loop 200 carry_in := carry_out; -- of previous bit 201 result(index) := op1(index) xor (not op2(index)) xor carry_in; 202 carry_out := (op1(index) and (not op2(index))) 203 or (carry_in and (op1(index) xor (not op2(index)))); 204 end loop; 205 end if; 206 return result; 207 end function "-"; 208 209 procedure bv_addu ( bv1, bv2 : in bit_vector; 210 bv_result : out bit_vector; 211 overflow : out boolean ) is 212 213 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 214 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 215 variable result : bit_vector(bv_result'length - 1 downto 0); 216 variable carry : bit := '0'; 217 218 begin 219 if bv1'length /= bv2'length or bv1'length /= bv_result'length then 220 report "bv_addu: operands of different lengths" 221 severity failure; 222 else 223 for index in result'reverse_range loop 224 result(index) := op1(index) xor op2(index) xor carry; 225 carry := (op1(index) and op2(index)) 226 or (carry and (op1(index) xor op2(index))); 227 end loop; 228 bv_result := result; 229 overflow := carry = '1'; 230 end if; 231 end procedure bv_addu; 232 233 function bv_addu ( bv1, bv2 : in bit_vector ) return bit_vector is 234 235 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 236 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 237 variable result : bit_vector(bv1'length - 1 downto 0); 238 variable carry : bit := '0'; 239 240 begin 241 if bv1'length /= bv2'length then 242 report "bv_addu: operands of different lengths" 243 severity failure; 244 else 245 for index in result'reverse_range loop 246 result(index) := op1(index) xor op2(index) xor carry; 247 carry := (op1(index) and op2(index)) 248 or (carry and (op1(index) xor op2(index))); 249 end loop; 250 end if; 251 return result; 252 end function bv_addu; 253 254 procedure bv_subu ( bv1, bv2 : in bit_vector; 255 bv_result : out bit_vector; 256 overflow : out boolean ) is 257 258 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 259 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 260 variable result : bit_vector(bv_result'length - 1 downto 0); 261 variable borrow : bit := '0'; 262 263 begin 264 if bv1'length /= bv2'length or bv1'length /= bv_result'length then 265 report "bv_subu: operands of different lengths" 266 severity failure; 267 else 268 for index in result'reverse_range loop 269 result(index) := op1(index) xor op2(index) xor borrow; 270 borrow := (not op1(index) and op2(index)) 271 or (borrow and not (op1(index) xor op2(index))); 272 end loop; 273 bv_result := result; 274 overflow := borrow = '1'; 275 end if; 276 end procedure bv_subu; 277 278 function bv_subu ( bv1, bv2 : in bit_vector ) return bit_vector is 279 280 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 281 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 282 variable result : bit_vector(bv1'length - 1 downto 0); 283 variable borrow : bit := '0'; 284 285 begin 286 if bv1'length /= bv2'length then 287 report "bv_subu: operands of different lengths" 288 severity failure; 289 else 290 for index in result'reverse_range loop 291 result(index) := op1(index) xor op2(index) xor borrow; 292 borrow := (not op1(index) and op2(index)) 293 or (borrow and not (op1(index) xor op2(index))); 294 end loop; 295 end if; 296 return result; 297 end function bv_subu; 298 299 procedure bv_neg ( bv : in bit_vector; 300 bv_result : out bit_vector; 301 overflow : out boolean ) is 302 303 constant zero : bit_vector(bv'range) := (others => '0'); 304 305 begin 306 bv_sub( zero, bv, bv_result, overflow ); 307 end procedure bv_neg; 308 309 310 function "-" ( bv : in bit_vector ) return bit_vector is 311 312 constant zero : bit_vector(bv'range) := (others => '0'); 313 314 begin 315 return zero - bv; 316 end function "-"; 317 318 procedure bv_mult ( bv1, bv2 : in bit_vector; 319 bv_result : out bit_vector; 320 overflow : out boolean ) is 321 322 variable negative_result : boolean; 323 variable op1 : bit_vector(bv1'range) := bv1; 324 variable op2 : bit_vector(bv2'range) := bv2; 325 variable multu_result : bit_vector(bv1'range); 326 variable multu_overflow : boolean; 327 variable abs_min_int : bit_vector(bv1'range) := (others => '0'); 328 329 begin 330 if bv1'length /= bv2'length or bv1'length /= bv_result'length then 331 report "bv_mult: operands of different lengths" 332 severity failure; 333 else 334 abs_min_int(bv1'left) := '1'; 335 negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1'); 336 if op1(op1'left) = '1' then 337 op1 := - bv1; 338 end if; 339 if op2(op2'left) = '1' then 340 op2 := - bv2; 341 end if; 342 bv_multu(op1, op2, multu_result, multu_overflow); 343 if negative_result then 344 overflow := multu_overflow or (multu_result > abs_min_int); 345 bv_result := - multu_result; 346 else 347 overflow := multu_overflow or (multu_result(multu_result'left) = '1'); 348 bv_result := multu_result; 349 end if; 350 end if; 351 end procedure bv_mult; 352 353 function "*" ( bv1, bv2 : in bit_vector ) return bit_vector is 354 355 variable negative_result : boolean; 356 variable op1 : bit_vector(bv1'range) := bv1; 357 variable op2 : bit_vector(bv2'range) := bv2; 358 variable result : bit_vector(bv1'range); 359 360 begin 361 if bv1'length /= bv2'length then 362 report """*"": operands of different lengths" 363 severity failure; 364 else 365 negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1'); 366 if op1(op1'left) = '1' then 367 op1 := - bv1; 368 end if; 369 if op2(op2'left) = '1' then 370 op2 := - bv2; 371 end if; 372 result := bv_multu(op1, op2); 373 if negative_result then 374 result := - result; 375 end if; 376 end if; 377 return result; 378 end function "*"; 379 380 procedure bv_multu ( bv1, bv2 : in bit_vector; 381 bv_result : out bit_vector; 382 overflow : out boolean ) is 383 384 alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1; 385 alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2; 386 constant len : natural := bv1'length; 387 constant accum_len : natural := len * 2; 388 variable accum : bit_vector(accum_len - 1 downto 0) := (others => '0'); 389 constant zero : bit_vector(accum_len - 1 downto len):= (others => '0'); 390 variable addu_overflow : boolean; 391 392 begin 393 if bv1'length /= bv2'length or bv1'length /= bv_result'length then 394 report "bv_multu: operands of different lengths" 395 severity failure; 396 else 397 for count in 0 to len - 1 loop 398 if op2(count) = '1' then 399 bv_addu( accum(count + len - 1 downto count), op1, 400 accum(count + len - 1 downto count), addu_overflow); 401 accum(count + len) := bit'val(boolean'pos(addu_overflow)); 402 end if; 403 end loop; 404 bv_result := accum(len - 1 downto 0); 405 overflow := accum(accum_len-1 downto len) /= zero; 406 end if; 407 end procedure bv_multu; 408 409 function bv_multu ( bv1, bv2 : in bit_vector ) return bit_vector is 410 411 -- Use bv_multu with overflow detection, but ignore overflow flag 412 413 variable result : bit_vector(bv1'range); 414 variable tmp_overflow : boolean; 415 416 begin 417 bv_multu(bv1, bv2, result, tmp_overflow); 418 return result; 419 end function bv_multu; 420 421 procedure bv_div ( bv1, bv2 : in bit_vector; 422 bv_result : out bit_vector; 423 div_by_zero : out boolean; 424 overflow : out boolean ) is 425 426 -- Need overflow, in case divide b"10...0" (min_int) by -1 427 -- Don't use bv_to_int, in case size bigger than host machine! 428 429 variable negative_result : boolean; 430 variable op1 : bit_vector(bv1'range) := bv1; 431 variable op2 : bit_vector(bv2'range) := bv2; 432 variable divu_result : bit_vector(bv1'range); 433 434 begin 435 if bv1'length /= bv2'length or bv1'length /= bv_result'length then 436 report "bv_div: operands of different lengths" 437 severity failure; 438 else 439 negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1'); 440 if op1(op1'left) = '1' then 441 op1 := - bv1; 442 end if; 443 if op2(op2'left) = '1' then 444 op2 := - bv2; 445 end if; 446 bv_divu(op1, op2, divu_result, div_by_zero); 447 if negative_result then 448 overflow := false; 449 bv_result := - divu_result; 450 else 451 overflow := divu_result(divu_result'left) = '1'; 452 bv_result := divu_result; 453 end if; 454 end if; 455 end procedure bv_div; 456 457 function "/" ( bv1, bv2 : in bit_vector ) return bit_vector is 458 459 variable negative_result : boolean; 460 variable op1 : bit_vector(bv1'range) := bv1; 461 variable op2 : bit_vector(bv2'range) := bv2; 462 variable result : bit_vector(bv1'range); 463 464 begin 465 if bv1'length /= bv2'length then 466 report """/"": operands of different lengths" 467 severity failure; 468 else 469 negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1'); 470 if op1(op1'left) = '1' then 471 op1 := - bv1; 472 end if; 473 if op2(op2'left) = '1' then 474 op2 := - bv2; 475 end if; 476 result := bv_divu(op1, op2); 477 if negative_result then 478 result := - result; 479 end if; 480 end if; 481 return result; 482 end function "/"; 483 484 procedure bv_divu ( bv1, bv2 : in bit_vector; 485 bv_quotient : out bit_vector; 486 bv_remainder : out bit_vector; 487 div_by_zero : out boolean ) is 488 489 constant len : natural := bv1'length; 490 constant zero_divisor : bit_vector(len-1 downto 0) := (others => '0'); 491 alias dividend : bit_vector(bv1'length-1 downto 0) is bv1; 492 variable divisor : bit_vector(bv2'length downto 0) := '0' & bv2; 493 variable quotient : bit_vector(len-1 downto 0); 494 variable remainder : bit_vector(len downto 0) := (others => '0'); 495 variable ignore_overflow : boolean; 496 497 begin 498 if bv1'length /= bv2'length 499 or bv1'length /= bv_quotient'length or bv1'length /= bv_remainder'length then 500 report "bv_divu: operands of different lengths" 501 severity failure; 502 else 503 -- check for zero divisor 504 if bv2 = zero_divisor then 505 div_by_zero := true; 506 return; 507 end if; 508 -- perform division 509 for iter in len-1 downto 0 loop 510 if remainder(len) = '0' then 511 remainder := remainder sll 1; 512 remainder(0) := dividend(iter); 513 bv_sub(remainder, divisor, remainder, ignore_overflow); 514 else 515 remainder := remainder sll 1; 516 remainder(0) := dividend(iter); 517 bv_add(remainder, divisor, remainder, ignore_overflow); 518 end if; 519 quotient(iter) := not remainder(len); 520 end loop; 521 if remainder(len) = '1' then 522 bv_add(remainder, divisor, remainder, ignore_overflow); 523 end if; 524 bv_quotient := quotient; 525 bv_remainder := remainder(len - 1 downto 0); 526 div_by_zero := false; 527 end if; 528 end procedure bv_divu; 529 530 procedure bv_divu ( bv1, bv2 : in bit_vector; 531 bv_quotient : out bit_vector; 532 div_by_zero : out boolean ) is 533 534 variable ignore_remainder : bit_vector(bv_quotient'range); 535 536 begin 537 bv_divu(bv1, bv2, bv_quotient, ignore_remainder, div_by_zero); 538 end procedure bv_divu; 539 540 function bv_divu ( bv1, bv2 : in bit_vector ) return bit_vector is 541 542 variable result : bit_vector(bv1'range); 543 variable tmp_div_by_zero : boolean; 544 545 begin 546 bv_divu(bv1, bv2, result, tmp_div_by_zero); 547 return result; 548 end function bv_divu; 549 550 ---------------------------------------------------------------- 551 -- Arithmetic comparison operators. 552 -- Perform comparisons on bit vector encoded signed integers. 553 -- (For unsigned integers, built in lexical comparison does 554 -- the required operation.) 555 ---------------------------------------------------------------- 556 557 function bv_lt ( bv1, bv2 : in bit_vector ) return boolean is 558 559 variable tmp1 : bit_vector(bv1'range) := bv1; 560 variable tmp2 : bit_vector(bv2'range) := bv2; 561 562 begin 563 assert bv1'length = bv2'length 564 report "bv_lt: operands of different lengths" 565 severity failure; 566 tmp1(tmp1'left) := not tmp1(tmp1'left); 567 tmp2(tmp2'left) := not tmp2(tmp2'left); 568 return tmp1 < tmp2; 569 end function bv_lt; 570 571 function bv_le ( bv1, bv2 : in bit_vector ) return boolean is 572 573 variable tmp1 : bit_vector(bv1'range) := bv1; 574 variable tmp2 : bit_vector(bv2'range) := bv2; 575 576 begin 577 assert bv1'length = bv2'length 578 report "bv_le: operands of different lengths" 579 severity failure; 580 tmp1(tmp1'left) := not tmp1(tmp1'left); 581 tmp2(tmp2'left) := not tmp2(tmp2'left); 582 return tmp1 <= tmp2; 583 end function bv_le; 584 585 function bv_gt ( bv1, bv2 : in bit_vector ) return boolean is 586 587 variable tmp1 : bit_vector(bv1'range) := bv1; 588 variable tmp2 : bit_vector(bv2'range) := bv2; 589 590 begin 591 assert bv1'length = bv2'length 592 report "bv_gt: operands of different lengths" 593 severity failure; 594 tmp1(tmp1'left) := not tmp1(tmp1'left); 595 tmp2(tmp2'left) := not tmp2(tmp2'left); 596 return tmp1 > tmp2; 597 end function bv_gt; 598 599 function bv_ge ( bv1, bv2 : in bit_vector ) return boolean is 600 601 variable tmp1 : bit_vector(bv1'range) := bv1; 602 variable tmp2 : bit_vector(bv2'range) := bv2; 603 604 begin 605 assert bv1'length = bv2'length 606 report "bv_ged: operands of different lengths" 607 severity failure; 608 tmp1(tmp1'left) := not tmp1(tmp1'left); 609 tmp2(tmp2'left) := not tmp2(tmp2'left); 610 return tmp1 >= tmp2; 611 end function bv_ge; 612 613 ---------------------------------------------------------------- 614 -- Extension operators - convert a bit vector to a longer one 615 ---------------------------------------------------------------- 616 617 function bv_sext ( bv : in bit_vector; 618 length : in natural ) return bit_vector is 619 620 alias bv_norm : bit_vector(bv'length - 1 downto 0) is bv; 621 variable result : bit_vector(length - 1 downto 0) := (others => bv(bv'left)); 622 variable src_length : natural := bv'length; 623 624 begin 625 if src_length > length then 626 src_length := length; 627 end if; 628 result(src_length - 1 downto 0) := bv_norm(src_length - 1 downto 0); 629 return result; 630 end function bv_sext; 631 632 function bv_zext ( bv : in bit_vector; 633 length : in natural ) return bit_vector is 634 635 alias bv_norm : bit_vector(bv'length - 1 downto 0) is bv; 636 variable result : bit_vector(length - 1 downto 0) := (others => '0'); 637 variable src_length : natural := bv'length; 638 639 begin 640 if src_length > length then 641 src_length := length; 642 end if; 643 result(src_length - 1 downto 0) := bv_norm(src_length - 1 downto 0); 644 return result; 645 end function bv_zext; 646 647end package body bv_arithmetic; 648