Electrical – creating a bcd squarer using verilog

binaryhdlsquareverilogxilinx

Basically, I am using a lookup table to output in bcd the square of a single digit bcd.

The problem that I have is that it is not outputting the correct answer.

For example: the result I get for the square of these number are:

1 = 1

2 = 4

4 = 10

5 = 19

10 = 64

as you can see I have to separate MBCD and LBCD and then concatenate them.

Here is my code:

module bcdsquarer(input[3:0]bcdin, output[7:4]Mbcd, output[3:0]Lbcd);
parameter msb = 16;
parameter lsb = 8;
reg [lsb-1:0]ROM[0:msb-1];
integer i;
initial 
    begin
    for(i=0; i<16; i = i+1)
        begin
            ROM[i] = i**2;
        end
    end
    assign {Mbcd,Lbcd} = ROM[bcdin];
endmodule

do anyone see where I made a mistake at?

edit:
Okay, So know I have to convert from binary to bcd. I have a code that converts, but how do I implement it with my bcdsquarer?

here is my code

module B2BCD(B,hundreds,tens,ones);
    input [7:0] B;
    output [3:0] hundreds;
    output [3:0] tens;
    output [3:0] ones;
    integer x;
    reg [3:0] hundreds, tens, ones;
    always @(B)
    begin
        x=B;
       hundreds=0; tens=0; ones = 0;
       if(x>99)begin hundreds =hundreds +1; x =x-100; end
       if(x>99)begin hundreds =hundreds +1; x =x-100; end
       repeat(9)
       begin
       if(x>9)begin tens = tens +1; x =x-10; end
       end

       ones =x;
    end
endmodule

I tried implementing it like this: (I just get x for my results now)

module bcdsquarer(bcdin,Mbcd,Lbcd,tens,ones);
parameter msb = 16;
parameter lsb = 8;

input[3:0]bcdin;

output[7:4]Mbcd;
output[3:0]Lbcd;

output [3:0] tens;
output [3:0] ones;

integer x;
reg[3:0] tens;
reg[3:0] ones;
    always @(bcdin)
    begin
        x=bcdin;
       tens=0; ones = 0;
       begin
       if(x>9)begin tens = tens +1; x =x-10; end
       end

       ones =x;
    end

assign Mbcd = tens;
assign Lbcd = ones;

reg [lsb-1:0]ROM[0:msb-1];
integer i;
initial 
    begin
    for(i=0; i<16; i = i+1)
        begin
            ROM[i] = i**2;
        end
    end
    assign {Mbcd,Lbcd} = ROM[bcdin];
endmodule

Best Answer

Basically Verilog operations are done in binary not BCD. So if you do something like i**2 the result will be in binary. Splitting the nibbles doesn't convert binary to BCD.

You have two options. Either:

  1. Continue and implement a binary to BCD conversion - you could do this as a function, which because it is used in an initial block shouldn't infer any hardware assuming it is something the synthesizer can calculate. Or

  2. Compute all the values before hand, and simply initialise the LUT you have designed with the precomputed values. This is by far the easiest way, and to be honest likely (or so I've found) the usual way of doing it.

In the latter option you can do this several ways. One is to use something like Excel to compute a table of values and initialise the LUT from that - e.g. by reading the values in turn from a file (Verilog has macros for this like $readmem).

Alternatively if you are feeling adventurous, you can create a script (e.g. TCL) which creates the values and generates either the a Verilog file containing the code for the whole LUT including initialation, or creates a memory initialisation file which you can load into your LUT. This option is not really useful for this particular example, but great for more complex ones, perhaps save it for once you've gained more experience.

Related Topic