URL
https://opencores.org/ocsvn/ft816float/ft816float/trunk
Subversion Repositories ft816float
[/] [ft816float/] [trunk/] [rtl/] [verilog2/] [BCDMath.sv] - Rev 80
Compare with Previous | Blame | View Log
`timescale 1ns / 1ps// ============================================================================// __// \\__/ o\ (C) 2012-2022 Robert Finch, Waterloo// \ __ / All rights reserved.// \/_// robfinch<remove>@finitron.ca// ||//// BCDMath.sv//// BSD 3-Clause License// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are met://// 1. Redistributions of source code must retain the above copyright notice, this// list of conditions and the following disclaimer.//// 2. Redistributions in binary form must reproduce the above copyright notice,// this list of conditions and the following disclaimer in the documentation// and/or other materials provided with the distribution.//// 3. Neither the name of the copyright holder nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.//// ============================================================================//// Could use the following approach for add/sub but it ends up being larger// than using an adjustment lookup table.module BCDAddNyb(ci,a,b,o,c);input ci; // carry inputinput [3:0] a;input [3:0] b;output [3:0] o;output c;wire c0;reg [4:0] hsN0;always @*beginhsN0 = a[3:0] + b[3:0] + ci;if (hsN0 > 5'd9)hsN0 = hsN0 + 3'd6;endassign o = hsN0[3:0];assign c = hsN0[4];endmodulemodule BCDAdd(ci,a,b,o,c);input ci; // carry inputinput [7:0] a;input [7:0] b;output [7:0] o;output c;wire c0,c1;wire [4:0] hsN0 = a[3:0] + b[3:0] + ci;wire [4:0] hsN1 = a[7:4] + b[7:4] + c0;BCDAddAdjust u1 (hsN0,o[3:0],c0);BCDAddAdjust u2 (hsN1,o[7:4],c);endmodulemodule BCDAdd4(ci,a,b,o,c,c8);input ci; // carry inputinput [15:0] a;input [15:0] b;output [15:0] o;output c;output c8;wire c0,c1,c2;assign c8 = c1;wire [4:0] hsN0 = a[3:0] + b[3:0] + ci;wire [4:0] hsN1 = a[7:4] + b[7:4] + c0;wire [4:0] hsN2 = a[11:8] + b[11:8] + c1;wire [4:0] hsN3 = a[15:12] + b[15:12] + c2;BCDAddAdjust u1 (hsN0,o[3:0],c0);BCDAddAdjust u2 (hsN1,o[7:4],c1);BCDAddAdjust u3 (hsN2,o[11:8],c2);BCDAddAdjust u4 (hsN3,o[15:12],c);endmodulemodule BCDAddNClk(clk,ci,a,b,o,co);parameter N=25;input clk;input ci;input [N*4-1:0] a;input [N*4-1:0] b;output reg [N*4-1:0] o;output reg co;reg [N-1:0] cg;wire [N*4-1:0] s;reg [N*4-1:0] on [0:3];reg [3:0] cn;genvar g;generate begin :gAddfor (g = 0; g < N; g = g + 1)BCDAddNyb u1 (.ci(g==0 ? ci : cg[g-1]),.a(a[g*4+3:g*4]),.b(b[g*4+3:g*4]),.o(s[g*4+3:g*4]),.c(cg[g]));endendgeneratealways_ff @(posedge clk)on[0] <= s;always_ff @(posedge clk)on[1] <= on[0];always_ff @(posedge clk)on[2] <= on[1];always_ff @(posedge clk)o <= on[2];always_ff @(posedge clk)cn[0] <= cg[N-1];always_ff @(posedge clk)cn[1] <= cn[0];always_ff @(posedge clk)cn[2] <= cn[1];always_ff @(posedge clk)co <= cn[2];endmodulemodule BCDAddN(ci,a,b,o,co);parameter N=25;input ci;input [N*4-1:0] a;input [N*4-1:0] b;output [N*4-1:0] o;output co;reg [N-1:0] cg;wire [N*4-1:0] s;genvar g;generate begin :gAddfor (g = 0; g < N; g = g + 1)BCDAddNyb u1 (.ci(g==0 ? ci : cg[g-1]),.a(a[g*4+3:g*4]),.b(b[g*4+3:g*4]),.o(s[g*4+3:g*4]),.c(cg[g]));endendgenerateassign o = s;assign co = cg[N-1];endmodule/*module BCDAddN(ci,a,b,o,co);parameter N=24;input ci; // carry inputinput [N*4-1:0] a;input [N*4-1:0] b;output [N*4-1:0] o;output co;genvar g;generate begin : gBCDAddNreg [4:0] hsN [0:N-1];wire [N:0] c;assign c[0] = ci;assign co = c[N];for (g = 0; g < N; g = g + 1)always @*hsN[g] = a[g*4+3:g*4] + b[g*4+3:g*4] + c[g];for (g = 0; g < N; g = g + 1)BCDAddAdjust u1 (hsN[g],o[g*4+3:g*4],c[g+1]);endendgenerateendmodule*/module BCDAddAdjust(i,o,c);input [4:0] i;output [3:0] o;reg [3:0] o;output c;reg c;always @(i)case(i)5'h0: begin o = 4'h0; c = 1'b0; end5'h1: begin o = 4'h1; c = 1'b0; end5'h2: begin o = 4'h2; c = 1'b0; end5'h3: begin o = 4'h3; c = 1'b0; end5'h4: begin o = 4'h4; c = 1'b0; end5'h5: begin o = 4'h5; c = 1'b0; end5'h6: begin o = 4'h6; c = 1'b0; end5'h7: begin o = 4'h7; c = 1'b0; end5'h8: begin o = 4'h8; c = 1'b0; end5'h9: begin o = 4'h9; c = 1'b0; end5'hA: begin o = 4'h0; c = 1'b1; end5'hB: begin o = 4'h1; c = 1'b1; end5'hC: begin o = 4'h2; c = 1'b1; end5'hD: begin o = 4'h3; c = 1'b1; end5'hE: begin o = 4'h4; c = 1'b1; end5'hF: begin o = 4'h5; c = 1'b1; end5'h10: begin o = 4'h6; c = 1'b1; end5'h11: begin o = 4'h7; c = 1'b1; end5'h12: begin o = 4'h8; c = 1'b1; end5'h13: begin o = 4'h9; c = 1'b1; enddefault: begin o = 4'h9; c = 1'b1; endendcaseendmodulemodule BCDSubAdjust(i,o,c);input [4:0] i;output [3:0] o;reg [3:0] o;output c;reg c;always @(i)case(i)5'h0: begin o = 4'h0; c = 1'b0; end5'h1: begin o = 4'h1; c = 1'b0; end5'h2: begin o = 4'h2; c = 1'b0; end5'h3: begin o = 4'h3; c = 1'b0; end5'h4: begin o = 4'h4; c = 1'b0; end5'h5: begin o = 4'h5; c = 1'b0; end5'h6: begin o = 4'h6; c = 1'b0; end5'h7: begin o = 4'h7; c = 1'b0; end5'h8: begin o = 4'h8; c = 1'b0; end5'h9: begin o = 4'h9; c = 1'b0; end5'h16: begin o = 4'h0; c = 1'b1; end5'h17: begin o = 4'h1; c = 1'b1; end5'h18: begin o = 4'h2; c = 1'b1; end5'h19: begin o = 4'h3; c = 1'b1; end5'h1A: begin o = 4'h4; c = 1'b1; end5'h1B: begin o = 4'h5; c = 1'b1; end5'h1C: begin o = 4'h6; c = 1'b1; end5'h1D: begin o = 4'h7; c = 1'b1; end5'h1E: begin o = 4'h8; c = 1'b1; end5'h1F: begin o = 4'h9; c = 1'b1; enddefault: begin o = 4'h9; c = 1'b1; endendcaseendmodule// Multiply two BCD digits// Method used is table lookupmodule BCDMul1(a,b,o);input [3:0] a;input [3:0] b;output [7:0] o;reg [7:0] o;always @(a or b)casex({a,b})8'h00: o = 8'h00;8'h01: o = 8'h00;8'h02: o = 8'h00;8'h03: o = 8'h00;8'h04: o = 8'h00;8'h05: o = 8'h00;8'h06: o = 8'h00;8'h07: o = 8'h00;8'h08: o = 8'h00;8'h09: o = 8'h00;8'h10: o = 8'h00;8'h11: o = 8'h01;8'h12: o = 8'h02;8'h13: o = 8'h03;8'h14: o = 8'h04;8'h15: o = 8'h05;8'h16: o = 8'h06;8'h17: o = 8'h07;8'h18: o = 8'h08;8'h19: o = 8'h09;8'h20: o = 8'h00;8'h21: o = 8'h02;8'h22: o = 8'h04;8'h23: o = 8'h06;8'h24: o = 8'h08;8'h25: o = 8'h10;8'h26: o = 8'h12;8'h27: o = 8'h14;8'h28: o = 8'h16;8'h29: o = 8'h18;8'h30: o = 8'h00;8'h31: o = 8'h03;8'h32: o = 8'h06;8'h33: o = 8'h09;8'h34: o = 8'h12;8'h35: o = 8'h15;8'h36: o = 8'h18;8'h37: o = 8'h21;8'h38: o = 8'h24;8'h39: o = 8'h27;8'h40: o = 8'h00;8'h41: o = 8'h04;8'h42: o = 8'h08;8'h43: o = 8'h12;8'h44: o = 8'h16;8'h45: o = 8'h20;8'h46: o = 8'h24;8'h47: o = 8'h28;8'h48: o = 8'h32;8'h49: o = 8'h36;8'h50: o = 8'h00;8'h51: o = 8'h05;8'h52: o = 8'h10;8'h53: o = 8'h15;8'h54: o = 8'h20;8'h55: o = 8'h25;8'h56: o = 8'h30;8'h57: o = 8'h35;8'h58: o = 8'h40;8'h59: o = 8'h45;8'h60: o = 8'h00;8'h61: o = 8'h06;8'h62: o = 8'h12;8'h63: o = 8'h18;8'h64: o = 8'h24;8'h65: o = 8'h30;8'h66: o = 8'h36;8'h67: o = 8'h42;8'h68: o = 8'h48;8'h69: o = 8'h54;8'h70: o = 8'h00;8'h71: o = 8'h07;8'h72: o = 8'h14;8'h73: o = 8'h21;8'h74: o = 8'h28;8'h75: o = 8'h35;8'h76: o = 8'h42;8'h77: o = 8'h49;8'h78: o = 8'h56;8'h79: o = 8'h63;8'h80: o = 8'h00;8'h81: o = 8'h08;8'h82: o = 8'h16;8'h83: o = 8'h24;8'h84: o = 8'h32;8'h85: o = 8'h40;8'h86: o = 8'h48;8'h87: o = 8'h56;8'h88: o = 8'h64;8'h89: o = 8'h72;8'h90: o = 8'h00;8'h91: o = 8'h09;8'h92: o = 8'h18;8'h93: o = 8'h27;8'h94: o = 8'h36;8'h95: o = 8'h45;8'h96: o = 8'h54;8'h97: o = 8'h63;8'h98: o = 8'h72;8'h99: o = 8'h81;default: o = 8'h00;endcaseendmodule// Multiply two pairs of BCD digits// handles from 0x0 to 99x99module BCDMul2(a,b,o);input [7:0] a;input [7:0] b;output [15:0] o;wire [7:0] p1,p2,p3,p4;wire [15:0] s1;BCDMul1 u1 (a[3:0],b[3:0],p1);BCDMul1 u2 (a[7:4],b[3:0],p2);BCDMul1 u3 (a[3:0],b[7:4],p3);BCDMul1 u4 (a[7:4],b[7:4],p4);BCDAdd4 u5 (1'b0,{p4,p1},{4'h0,p2,4'h0},s1);BCDAdd4 u6 (1'b0,s1,{4'h0,p3,4'h0},o);endmodulemodule BCDMul4(a,b,o);input [15:0] a;input [15:0] b;output [31:0] o;wire [15:0] p1,p2,p3,p4;wire [31:0] s1;BCDMul2 u1 (a[7:0],b[7:0],p1);BCDMul2 u2 (a[15:8],b[7:0],p2);BCDMul2 u3 (a[7:0],b[15:8],p3);BCDMul2 u4 (a[15:8],b[15:8],p4);BCDAddN #(.N(8)) u5 (1'b0,{p4,p1},{8'h0,p2,8'h0},s1);BCDAddN #(.N(8)) u6 (1'b0,s1,{8'h0,p3,8'h0},o);endmodulemodule BCDMul8(a,b,o);input [31:0] a;input [31:0] b;output [63:0] o;wire [31:0] p1,p2,p3,p4;wire [63:0] s1;BCDMul4 u1 (a[15:0],b[15:0],p1);BCDMul4 u2 (a[31:16],b[15:0],p2);BCDMul4 u3 (a[15:0],b[31:16],p3);BCDMul4 u4 (a[31:16],b[31:16],p4);BCDAddN #(.N(16)) u5 (1'b0,{p4,p1},{16'h0,p2,16'h0},s1);BCDAddN #(.N(16)) u6 (1'b0,s1,{16'h0,p3,16'h0},o);endmodulemodule BCDMul16(a,b,o);input [63:0] a;input [63:0] b;output [127:0] o;wire [63:0] p1,p2,p3,p4;wire [127:0] s1;BCDMul8 u1 (a[31:0],b[31:0],p1);BCDMul8 u2 (a[63:32],b[31:0],p2);BCDMul8 u3 (a[31:0],b[63:32],p3);BCDMul8 u4 (a[63:32],b[63:32],p4);BCDAddN #(.N(32)) u5 (1'b0,{p4,p1},{32'h0,p2,32'h0},s1);BCDAddN #(.N(32)) u6 (1'b0,s1,{32'h0,p3,32'h0},o);endmodulemodule BCDMul32(a,b,o);input [127:0] a;input [127:0] b;output [255:0] o;wire [127:0] p1,p2,p3,p4;wire [255:0] s1;BCDMul16 u1 (a[63:0],b[63:0],p1);BCDMul16 u2 (a[127:64],b[63:0],p2);BCDMul16 u3 (a[63:0],b[127:64],p3);BCDMul16 u4 (a[127:64],b[127:64],p4);BCDAddN #(.N(64)) u5 (1'b0,{p4,p1},{64'h0,p2,64'h0},s1);BCDAddN #(.N(64)) u6 (1'b0,s1,{64'h0,p3,64'h0},o);endmodulemodule BCDMul_tb();wire [15:0] o1,o2,o3,o4;BCDMul2 u1 (8'h00,8'h00,o1);BCDMul2 u2 (8'h99,8'h99,o2);BCDMul2 u3 (8'h25,8'h18,o3);BCDMul2 u4 (8'h37,8'h21,o4);endmodulemodule BinToBCD(i, o);input [7:0] i;output [11:0] o;reg [11:0] tbl [0:255];genvar g;generate begin : gTblreg [3:0] n0 [0:255];reg [3:0] n1 [0:255];reg [3:0] n2 [0:255];for (g = 0; g < 256; g = g + 1) begininitial beginn0[g] = g % 10;n1[g] = g / 10;n2[g] = g / 100;tbl[g] <= {n2[g],n1[g],n0[g]};endendassign o = tbl[i];endendgenerateendmodule// Perform a logical shift to the right.module BCDSRL(ci, i, o, co);parameter N=4;input ci;input [N*4-1:0] i;output reg [N*4-1:0] o;output co;reg [N:0] c;genvar g;generate beginalways @*c[N] = ci;for (g = N - 1; g >= 0; g = g - 1)always @*c[g] = i[g*4];for (g = N - 1; g >= 0; g = g - 1)always @*begino[g*4+3:g*4] = {1'b0,i[g*4+3:g*4+1]};// Because there is a divide by two, the value will range between 0 and 4.// Adding 5 keeps it within deicmal boundaries of 0 to 9. No carry can be// generatedif (c[N+1])o[g*4+3:g*4] = o[g*4+3:g*4] + 4'd5;endassign co = c[0];endendgenerateendmodule
