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 021111307 USA

19


20

 

21



22

 $Id: bv_arithmetic_body.vhd,v 1.3 20011026 16:29:33 paw Exp $

23

 $Revision: 1.3 $

24



25

 

26


27

package 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_len1 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(len1 downto 0) := (others => '0');

491

alias dividend : bit_vector(bv1'length1 downto 0) is bv1;

492

variable divisor : bit_vector(bv2'length downto 0) := '0' & bv2;

493

variable quotient : bit_vector(len1 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 len1 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


647

end package body bv_arithmetic;
