From d89da3480eeafdfa25a03096c7a45b04b9f0663d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Marczewski?= Date: Sat, 8 Dec 2018 11:09:20 +0100 Subject: [PATCH] Reimplement BCD using bit shifts --- bcd.v | 27 +++++++++++++++++++++++++++ bcd_tb.v | 26 ++++++++++++++++++++++++++ cpu.v | 43 ++++++++++++++----------------------------- 3 files changed, 67 insertions(+), 29 deletions(-) create mode 100644 bcd.v create mode 100644 bcd_tb.v diff --git a/bcd.v b/bcd.v new file mode 100644 index 0000000..31f92c8 --- /dev/null +++ b/bcd.v @@ -0,0 +1,27 @@ +`default_nettype none + +module bcd(input wire [7:0] abc, + output wire [1:0] a, + output reg [3:0] b, + output reg [3:0] c); + assign a = abc >= 200 ? 2 : abc >= 100 ? 1 : 0; + wire [6:0] bc = abc - 100 * a; + + // See Hacker's Delight, Integer division by constants: + // https://www.hackersdelight.org/divcMore.pdf + reg [6:0] q; + reg [3:0] r; + always @(*) begin + q = (bc >> 1) + (bc >> 2); + q = q + (q >> 4); + q = q >> 3; + r = bc - q * 10; + if (r < 10) begin + b = q; + c = r; + end else begin + b = q + 1; + c = r - 10; + end + end +endmodule diff --git a/bcd_tb.v b/bcd_tb.v new file mode 100644 index 0000000..07665d3 --- /dev/null +++ b/bcd_tb.v @@ -0,0 +1,26 @@ +`include "bcd.v" + +module top; + reg [7:0] abc = 0; + wire [1:0] a; + wire [3:0] b, c; + + bcd bcd0(abc, a, b, c); + + initial begin + $monitor($time, " %d -> %d %d %d", abc, a, b, c); + $dumpfile(`VCD_FILE); + $dumpvars; + + repeat (256) begin + #1; + if (!(a < 10 && b < 10 && c < 10)) + $fatal(1, "bad result"); + if (!(abc == a * 100 + b * 10 + c)) + $fatal(2, "bad result"); + + abc += 1; + end + #1 $finish; + end +endmodule diff --git a/cpu.v b/cpu.v index 1643550..09e9918 100644 --- a/cpu.v +++ b/cpu.v @@ -1,3 +1,5 @@ +`include "bcd.v" + module cpu(input wire clk, output wire [11:0] debug_pc); assign debug_pc = pc; @@ -50,17 +52,9 @@ module cpu(input wire clk, output wire [11:0] debug_pc); reg[4:0] state = STATE_FETCH_HI; - /* - BCD algorithm: - 1. STATE_BCD_1: Store hundreds digit, remove it from vx - 2. STATE_BCD_2: Keep removing 10 from vx to calculate tens digit, store it - 3. STATE_BCD_3: Store rest of vx as ones digit - */ - // BCD first digit - wire [1:0] bcd_vx_1 = vx >= 200 ? 2 : vx >= 100 ? 1 : 0; - // BCD second digit - reg [3:0] bcd_vx_2; - wire bcd_vx_2_ready = vx < 10; + wire [1:0] bcd_1; + wire [3:0] bcd_2, bcd_3; + bcd bcd0(vx, bcd_1, bcd_2, bcd_3); // Memory loads and stores always @(*) begin @@ -134,18 +128,17 @@ module cpu(input wire clk, output wire [11:0] debug_pc); STATE_BCD_1: begin mem_write = 1; mem_write_idx = addr; - mem_write_byte = {6'b0, bcd_vx_1}; + mem_write_byte = {6'b0, bcd_1}; + end + STATE_BCD_2: begin + mem_write = 1; + mem_write_idx = addr + 1; + mem_write_byte = {4'b0, bcd_2}; end - STATE_BCD_2: - if (bcd_vx_2_ready) begin - mem_write = 1; - mem_write_idx = addr + 1; - mem_write_byte = {4'b0, bcd_vx_2}; - end STATE_BCD_3: begin mem_write = 1; mem_write_idx = addr + 2; - mem_write_byte = vx; + mem_write_byte = {4'b0, bcd_3}; end endcase end @@ -238,18 +231,10 @@ module cpu(input wire clk, output wire [11:0] debug_pc); else begin transfer_counter <= transfer_counter - 1; end - STATE_BCD_1: begin + STATE_BCD_1: state <= STATE_BCD_2; - vx <= vx - bcd_vx_1 * 100; - bcd_vx_2 <= 0; - end STATE_BCD_2: - if (bcd_vx_2_ready) - state <= STATE_BCD_3; - else begin - bcd_vx_2 <= bcd_vx_2 + 1; - vx <= vx - 10; - end + state <= STATE_BCD_3; STATE_BCD_3: state <= STATE_FETCH_HI; STATE_DECODE: begin