diff options
Diffstat (limited to 'hdl/bin2bcd.sv')
| -rw-r--r-- | hdl/bin2bcd.sv | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/hdl/bin2bcd.sv b/hdl/bin2bcd.sv new file mode 100644 index 0000000..9b1609b --- /dev/null +++ b/hdl/bin2bcd.sv | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | `include "utils.svh" | ||
| 2 | |||
| 3 | module bin2bcd | ||
| 4 | #( BITS = 8 | ||
| 5 | , BASE = 10 | ||
| 6 | , BASE_BITS = $clog2(BASE) | ||
| 7 | , DIGITS = 3 // should be ceil[log(2**BITS) base BASE] which is hard to do in Verilog :-( | ||
| 8 | , MAX_SKIP = BITS | ||
| 9 | ) | ||
| 10 | ( input bit clk | ||
| 11 | , input bit reset | ||
| 12 | |||
| 13 | , output bit bin_ready | ||
| 14 | , input bit bin_valid `define bin_valid `past(bin_valid) | ||
| 15 | , input bit [BITS-1:0] bin_data `define bin_data `past(bin_data) | ||
| 16 | |||
| 17 | , input bit bcd_ready `define bcd_ready `past(bcd_ready) | ||
| 18 | , output bit bcd_valid | ||
| 19 | , output bit [DIGITS-1:0][BASE_BITS-1:0] bcd_data | ||
| 20 | ); | ||
| 21 | |||
| 22 | bit bin_b_valid; | ||
| 23 | bit [BITS-1:0] bin_b_data; | ||
| 24 | |||
| 25 | bit [DIGITS-1:0][BASE_BITS-1:0] bcd; | ||
| 26 | |||
| 27 | bit [$clog2(BITS):0] work; | ||
| 28 | |||
| 29 | always_ff @(posedge clk) begin | ||
| 30 | if (reset) begin | ||
| 31 | bin_ready = 0; | ||
| 32 | bcd_valid = 0; | ||
| 33 | bin_b_valid = 0; | ||
| 34 | end else begin | ||
| 35 | if (bin_ready && `bin_valid) begin | ||
| 36 | bin_b_valid = 1; | ||
| 37 | bin_b_data = `bin_data; | ||
| 38 | bcd = 0; | ||
| 39 | work = BITS; | ||
| 40 | for (int i = 0; i < BITS && i < MAX_SKIP; ++i) begin | ||
| 41 | if (bin_b_data[BITS-1]) break; | ||
| 42 | bin_b_data = { bin_b_data[BITS-2:0], 1'b0 }; | ||
| 43 | work = work - 1; | ||
| 44 | end | ||
| 45 | end | ||
| 46 | |||
| 47 | if (bin_b_valid && work != 0) begin | ||
| 48 | automatic bit carry = bin_b_data[BITS-1]; | ||
| 49 | for (int i = 0; i < DIGITS; ++i) begin | ||
| 50 | {carry, bcd[i]} = {bcd[i], carry}; | ||
| 51 | if ({carry, bcd[i]} >= BASE) begin | ||
| 52 | // verilator lint_off WIDTH | ||
| 53 | bcd[i] = {carry, bcd[i]} - BASE; | ||
| 54 | // verilator lint_on WIDTH | ||
| 55 | carry = 1; | ||
| 56 | end | ||
| 57 | end | ||
| 58 | assert(!carry); | ||
| 59 | |||
| 60 | bin_b_data = bin_b_data << 1; | ||
| 61 | |||
| 62 | work = work - 1; | ||
| 63 | end | ||
| 64 | |||
| 65 | if (`bcd_ready) bcd_valid = 0; | ||
| 66 | if (!bcd_valid && bin_b_valid && work == 0) begin | ||
| 67 | bcd_valid = 1; | ||
| 68 | bcd_data = bcd; | ||
| 69 | bin_b_valid = 0; | ||
| 70 | end | ||
| 71 | |||
| 72 | bin_ready = !bin_b_valid; | ||
| 73 | end | ||
| 74 | end | ||
| 75 | |||
| 76 | endmodule | ||
