module bin2bcd #( BITS = 8 , BASE = 10 ) ( input bit clk , input bit reset , output bit bin_ready , input bit bin_valid `define bin_valid $past(bin_valid) , input bit [BITS-1:0] bin_data `define bin_data $past(bin_data) , input bit bcd_ready `define bcd_ready $past(bcd_ready) , output bit bcd_valid , output bit [DIGITS-1:0][BASE_BITS-1:0] bcd_data ); // FIXME I don't think this works for odd bases localparam BASE_BITS = $clog2(BASE); localparam SLACK = (1 << BASE_BITS) - BASE; localparam DIGITS = $rtoi($ceil($ln(1 << BITS) / $ln(BASE))); localparam CARRY_TEST = $rtoi($ceil($itor(BASE) / 2)); localparam CARRY_ADD = $rtoi($ceil($itor(SLACK) / 2)); `ifdef DEBUG_BIN2BCD initial $display("%d BITS", BITS); initial $display("%d BASE", BASE); initial $display("%d BASE_BITS", BASE_BITS); initial $display("%d SLACK", SLACK); initial $display("%d DIGITS", DIGITS); initial $display("%d CARRY_TEST", CARRY_TEST); initial $display("%d CARRY_ADD", CARRY_ADD); initial for(int i = 0; i < BASE; i = i + 1) begin // verilator lint_off WIDTH automatic bit [BASE_BITS-1:0] n = i; automatic bit [BASE_BITS-1:0] a = n >= CARRY_TEST ? CARRY_ADD : 0; automatic bit [BASE_BITS-1:0] s = n + a; // verilator lint_on WIDTH automatic bit c; automatic bit [BASE_BITS-1:0] d; {c, d} = {s, 1'b0}; $display("\t\t(%x + %x => %x) * 2 => %x:%x", n, a, s, c, d); end `endif bit bin_b_valid; bit [BITS-1:0] bin_b_data; bit [DIGITS-1:0][BASE_BITS-1:0] bcd;; bit [$clog2(BITS):0] work; always_ff @(posedge clk) begin if (reset) begin bin_ready = 0; bcd_valid = 0; bin_b_valid = 0; end else begin if (bin_ready && `bin_valid) begin bin_b_valid = 1; bin_b_data = `bin_data; bcd = 0; work = BITS; for (int i = BITS; i > 0; i = i - 1) begin if (bin_b_data[BITS-1]) break; bin_b_data = { bin_b_data[BITS-2:0], 1'b0 }; work = work - 1; end end if (bin_b_valid && work != 0) begin for (int i = 0; i < DIGITS; i = i + 1) // verilator lint_off WIDTH if (bcd[i] >= CARRY_TEST) bcd[i] = bcd[i] + CARRY_ADD; // verilator lint_on WIDTH for (int i = DIGITS - 1; i > 0; i = i - 1) bcd[i] = { bcd[i][BASE_BITS-2:0], bcd[i-1][BASE_BITS-1] }; bcd[0] = { bcd[0][BASE_BITS-2:0], bin_b_data[BITS-1] }; bin_b_data = { bin_b_data[BITS-2:0], 1'b0 }; work = work - 1; end if (`bcd_ready) bcd_valid = 0; if (!bcd_valid && bin_b_valid && work == 0) begin bcd_valid = 1; bcd_data = bcd; bin_b_valid = 0; end bin_ready = !bin_b_valid; end end endmodule