Tried implementing Karatsuba multiplier for multiplying two binary numbers, the logic below works well for unsigned numbers, but getting incorrect answer when I change one of the inputs to a negative. In the example below a=1010011111000000(equals -88.25) and b= 0001010001000000(equals 20.25). The answer should be 11111001000001001111000000000000(equals:-1787.0625)but I end up getting the incorect answer. Have used fixed point logic, with inputs 16 bits and fraction point 8 bits, output being 32 bits with fraction bits 16.
module karatsuba( input signed [15:0] a,
input signed [15:0] b,
output signed [31:0] out
);
reg [15:0] ac,bd;
reg [31:0] t1;
reg [31:0]t2;
reg [24:0] psum;
initial begin
assign ac = a[15:8]*b[15:8];
assign bd = a[7:0]*b[7:0];
assign t2= bd;
assign t1={ac,16'b0000000000000000};
assign psum = {(a[15:8]+a[7:0])*(b[15:8]+b[7:0])-ac-bd,8'b00000000};
end
assign out= t1+psum+t2;
endmodule
module karatsuba_tb();
reg signed [15:0]a,b;
wire signed [31:0]out;
karatsuba uut(.a(a),.b(b),.out(out));
initial begin
a=16'b0101100001000000;
b=16'b0001010001000000;
end
endmodule
enter image description here
enter image description here
There are two issues pertaining to the signed multiply in the post:
Slices of vector variables (even slices of signed vectors) are treated as unsigned in Verilog. This is because when a slice is taken there is no way to identify the original sign bit, therefore it must be treated as unsigned
The solution is to cast the slices to signed so that Verilog treats them as signed. Like this:
assign ac = signed'(a[3:2]) * signed'(b[3:2]);
Make the line that defines the variable ac,bd to be treated as signed using the signed keyword (default is unsigned).
You will need to propagate these changes to other places in the posted code which have the same issues.
Here is a simplified version of the post using small numbers to illustrate the cast and keyword use:
module karatsuba(
input signed [3:0] a,
input signed [3:0] b
);
reg signed [3:0] ac;
assign ac = signed'(a[3:2]) * signed'(b[3:2]);
endmodule
module karatsuba_tb();
reg signed [3:0]a,b;
karatsuba uut(.a(a),.b(b));
initial begin
a = 4'b1110;
b = 4'b1111;
#1;
//
$display("---------------");
$display("uut.a[3:2] = %b",uut.a[3:2]);
$display("uut.b[3:2] = %b",uut.b[3:2]);
$display("uut.ac = %b",uut.ac);
$display("---------------");
//
$display("uut.a[3:2] = %d",signed'(uut.a[3:2]));
$display("uut.b[3:2] = %d",signed'(uut.b[3:2]));
$display("uut.ac = %d",uut.ac);
$display("---------------");
end
endmodule
The example displays this message at runtime:
---------------
uut.a[3:2] = 11
uut.b[3:2] = 11
uut.ac = 0001
---------------
uut.a[3:2] = -1
uut.b[3:2] = -1
uut.ac = 1
---------------
Related
If I reduce the number of bits after arithmetic right shift in verilog, do I still get the correct signed number? Is this valid?
number of bits reduced = shift value
A = 1110_1110
A>>>1
new A = 111_0111
Yes, but you should use three '>' not four and of course the new variable should be big enough:
wire signed [7:0] A,B;
wire signed [6:0] just_fits;
wire signed [5:0] oops;
assign B = A >>> 1; // Signed divide by two
assign just_fits = A >>> 1; // Signed divide by two
assign oops = A >>> 1; // Goes wrong
I am designing a signed verilog multiplier which I intend to use multiple times in another module.
My two inputs will be always s4.27 format. 1 bit signed, 4 bits of integer and 27 bits of fraction. My output has to be also in s4.27 format and I have to get the most accurate result out of it.
In C, the following not so perfect code snippet did the job.
int32_t mul(int32_t x, int32_t y)
{
int64_t mul = x;
mul *= y;
mul >>= 27;
return (int32_t) mul;
}
In verilog my simple version of code is given below,
`timescale 1ns/1ps
module fixed_multiplier (
i_a,
i_b,
o_p,
clk
);
input clk;
input signed [31:0] i_a;
input signed [31:0] i_b;
output signed [31:0] o_p;
wire signed [63:0] out;
assign out = i_a*i_b;
assign o_p = out;
endmodule
The above mentioned code has bugs that I know because I am not getting the desired results at all.
So my questions are,
(1) As this line "assign o_result = out;" seems crucial to me, how shall I do my assignments to my final output so that I get the correct and most accurate s4.27 format output? Please note, this output will be fed to an adder and the adder output will be again an input for the multiplier.
Above question being asked, I also tried with xor-ing of sign bits of both inputs and assigning [57:27] bits to final output. Did not suit me and resulted in overflow, while in C same inputs did not give any overflow error.
(2) With C I did not have any problem with fixed-point multiplication while in verilog I guess I am struggling as I am quite a newbie. Any suggestions what things to keep in mind while dealing with signed multiplication/addition?
Below is the testbench code,
`timescale 1ns / 1ps
module tb_mul;
// Inputs
reg clk;
reg [31:0] a;
reg [31:0] b;
// Outputs
wire [31:0] c;
fixed_multiplier mul_i (
.clk(clk),
.i_a(a),
.i_b(b),
.o_p(c)
);
initial begin
$dumpfile("test_mul.vcd");
$dumpvars(1);
$monitor ("a=%h,\tb=%h,\tc=%h",a,b,c);
a = 32'h10000000;
b = 32'h10000000;
$finish();
end
endmodule
Thank you in advance.
Your multiplier does not work like you think it does. Verilog will assume your multiplication will be unsigned, and will compute it as such. You might want to do something like the following:
wire [61:0] temp_out;
assign temp_out = i_multiplicand[30:0] * i_multiplier[30:0];
assign sign = i_multiplicand[31] ^ i_multiplier[31];
assign out = {sign, temp_out[57:37]};
i'm trying to multiply two 32 bit signed fractional number (1 sign bit, 8 integer bit, 23 fraction bit)
the first one is
32'b0_00000001_00000000000000000000000 // 1.00
the 2nd one is
32'b0_00000100_00000000000000000000000 // 4.00
when i do like this for example
output signed[31:0] a;
assign a = 32'b0_00000001_00000000000000000000000 * 32'b0_00000100_00000000000000000000000;
the results is zero? why it isn't 4?
kindly please help me in which part i am mistaken and what should i do. thank you very much
regards
Isaac
Because you are trying to assign a 64 bit value to a 32 bit wire, and Verilog will truncate the value, keeping only the lower 32 bits of the result, which is zero.
To have a proper result, you can do as this:
module mult;
reg [31:0] a = 32'b0_00000001_00000000000000000000000; // 1.0
reg [31:0] b = 32'b0_00000100_00000000000000000000000; // 4.0
reg [63:0] t;
reg [31:0] c;
initial begin
t = a * b;
c = t[54:23];
$display ("%b",c);
$finish;
end
endmodule
So I have been following a guide provided by EmbeddedMicro on producing a simple 16 bit CPU using their HDL Lucid. My goal is to convert this over to Verilog in Quartus II. The problem I am having is trying to store the bits allocated for the destination of my data into a specific range of bits inside the designated register. The second problem I am having is using a global Constant as one of case values. I was able to get around this by just replacing with the constant value. I have already added the include file into the project settings. I am still new to Verilog so their might be an abundant of bad code.
The error recieved is on line 57
shift_r.D[DEST] = DIN; //supposed to be storing the data coming in into register
Error Readout: Verilog Syntax Error, near text: "=". Check for and fix any syntax errors that appear immediately before or at the specified keyword
`include "CPU_8/my_incl.vh"
module CPU(CLK,RST,WRITE,READ,ADDRESS,DOUT,DIN);
input RST,CLK;
input [0:7] DIN; //DATA in
output reg [0:7] ADDRESS;
output reg [0:7] DOUT; //DATA OUT
output reg WRITE,READ;
reg [0:15] INST;
//I am not sure if i set up the array for my registers correctly either
shiftreg shift_r[0:15] (RST, CLK, D, Q); //initialize shift_r and create array of 16 registers.
//Implicit net is created for the D and Q above when generating block file
instRom_16 instRoms(ADDRESS, INST); //intialize InstRom_16 module
reg [0:3]OP; // opcode
reg [0:3]ARG1; // first arg
reg [0:3]ARG2; // second arg
reg [0:3]DEST; // destination arg
reg [0:7]CONSTANT; //Constant
always#(posedge CLK)
begin
WRITE = 0; // don't write
READ = 0; // don't read
ADDRESS = 8'b0; // don't care
DOUT = 8'b0; // don't care
instRoms.ADDRESS = shift_r.D[0]; //Set shift_reg to be program counter
shift_r.D = shift_r.Q[0] + 1; //increment program counter.
OP = instRoms.INST[15:12]; // opcode first 4 bits
DEST = instRoms.INST[11:8]; // destination one 4 bits
ARG1 = instRoms.INST[7:4]; // argument2 is next 4 bits
ARG2 = instRoms.INST[3:0]; // ARGUMENT2 is last 4 bits
CONSTANT = instRoms.INST[7:0];
//PERFORM OPERATIONS
case (OP)
4'd1: //tried to use `LOAD but that wouldn't point to the value in my include file
READ = 1; // request a read
//line that is failing
shift_r.D[DEST] = DIN; //supposed to be storing the data coming in into register
//4'd2:
endcase
end
endmodule
This is my include file
`ifndef _my_incl_vh_
`define _my_incl_vh_
`define NOP = 4'd0; // 0 filled
`define LOAD = 4'd1; // load
`endif
You made a little mistake:
shiftreg shift_r[0:15] (RST, CLK, D, Q);
Instantiates an array of shift_r, each instance of which has a RST, CLK, D and Q.
So shift_r.D[DEST] should become shift_r[DEST].D and shift_r.Q[0] should become shift_r[0].Q.
For shift_r.D, is guess you want a 0:15 vector. You will need to assign all 16 bits to an intermediate wire of 15 bits using e.g. a for loop.
I am designing a processor in Verilog. I'm working on the ALU, specifically the multiplier for the ALU. I can get the correct results when performing multiplication with small, positive numbers, but if I try to multiply signed numbers I get issues. When a positive number multiplies a negative the result will not sign extend all the way to 64 bits, and if two negative numbers are multiplied the number is incorrect altogether (sign and value). Can anyone see where the issue lies? I assumed I was not performing an arithmetic shift but I adjusted that and am still getting the wrong results.
module multiplier(
input[31:0] operand1,
input[31:0] operand2,
output reg [63:0] product
);
reg [64:0] prod;
reg [31:0] mcand;
reg [31:0] sum;
integer i = 0;
always #* begin
prod = {32'b0,operand1};
mcand = operand2;
for(i=0;i<32;i=i+1) begin
//test 0 bit of product
case(prod[0])
1'b0:begin //if prod[0] == 0, arithmetic shift right
prod = prod>>>1;
end
1'b1:begin //if prod[0] == 1, add multiplicand to upper 32
//bits and arithmetic shift right
prod = {(prod[63:32]+mcand[31:0]),prod[31:0]};
prod = prod>>>1;
end
endcase
end
product = prod[63:0];
end
endmodule
For >>> to perform signed shift the variable must be declared as signed.
reg signed [64:0] prod;
Short example on eda playground.
Also note that prod = {32'b0,operand1}; is not a sign extension. You should probably be using:
prod = { {32{operand[31]}}, operand1 };