J
James Harris
Guest
I've made a couple of attempts to write a multiplier to operate using
a technique presented in a Berkeley course video. The first version
did work (under Icarus) but it was rather ad-hoc and I hadn't really
learned anything from it. After a lot of head scratching trying to
guess how different constructs might (ought to?) be translated to
hardware I felt I could make it fully synchronous and the result is
below.
This stuff is fairly new to me I'd very much like to get some feedback
on the code. I can't change the basic technique which was part of the
problem definition but could there be any issue with getting the
circuit to synthesize and could it be made faster or less power
hungry? Is anything anomalous and could the design be made more
"normal"? Based on info in a separate CPU design course I've tried to
ensure that
* the combinatorial signal paths between registers are short and
balanced
* the fundamental add and shift operations can happen together in a
single cycle
* the counter decrement can happen in parallel with the addition.
These, I think, should be the slowest two operations as they are the
only ones with information to propagate between bit positions.
The basic idea for this multiplier mark 2 is that all the necessary
combinatorial signals are generated by continuous assignments and are
simply latched into registers on each leading clock edge - so all I
have to wait for between clocks is the combinatorial logic to settle.
Well, here's the code. *All* criticisms and suggestions welcome.
//
// Muliplier for N-bit operands, 2N-bit product
//
module mult2(product, finished, clock, input_a, input_b, reset);
parameter BITS = 32;
localparam LOG2BITS = $clog2(BITS + 1); // (May not need the + 1)
output reg [BITS * 2 - 1 : 0] product;
output reg finished;
input [BITS - 1 : 0] input_a, input_b;
input reset;
input clock;
reg [BITS - 1 : 0] multiplicand;
reg [LOG2BITS : 0] counter; // floor(log2(BITS)) + 1 in size
wire [BITS - 1 : 0] proxy = product[0] ? multiplicand : 0;
wire [BITS : 0] sum = product[BITS * 2 - 1 : BITS] + proxy; // NB. N
+ 1 bits
always @(posedge clock) begin
// $write("%b %b %b %d %b\n", clock, reset, finished, counter,
product);
if (reset == 1'b1) begin
multiplicand <= input_a;
product <= { 1'b0, input_b }; // Zero extend input_b
counter <= BITS;
finished <= 0;
end
else if (counter != 0) begin
product <= { sum, product[BITS - 1 : 1] }; // Add and shift
counter <= counter - 1;
end
else /* Counter is zero */ begin
finished <= 1;
end
end
endmodule
That's it. Hit me!
James
a technique presented in a Berkeley course video. The first version
did work (under Icarus) but it was rather ad-hoc and I hadn't really
learned anything from it. After a lot of head scratching trying to
guess how different constructs might (ought to?) be translated to
hardware I felt I could make it fully synchronous and the result is
below.
This stuff is fairly new to me I'd very much like to get some feedback
on the code. I can't change the basic technique which was part of the
problem definition but could there be any issue with getting the
circuit to synthesize and could it be made faster or less power
hungry? Is anything anomalous and could the design be made more
"normal"? Based on info in a separate CPU design course I've tried to
ensure that
* the combinatorial signal paths between registers are short and
balanced
* the fundamental add and shift operations can happen together in a
single cycle
* the counter decrement can happen in parallel with the addition.
These, I think, should be the slowest two operations as they are the
only ones with information to propagate between bit positions.
The basic idea for this multiplier mark 2 is that all the necessary
combinatorial signals are generated by continuous assignments and are
simply latched into registers on each leading clock edge - so all I
have to wait for between clocks is the combinatorial logic to settle.
Well, here's the code. *All* criticisms and suggestions welcome.
//
// Muliplier for N-bit operands, 2N-bit product
//
module mult2(product, finished, clock, input_a, input_b, reset);
parameter BITS = 32;
localparam LOG2BITS = $clog2(BITS + 1); // (May not need the + 1)
output reg [BITS * 2 - 1 : 0] product;
output reg finished;
input [BITS - 1 : 0] input_a, input_b;
input reset;
input clock;
reg [BITS - 1 : 0] multiplicand;
reg [LOG2BITS : 0] counter; // floor(log2(BITS)) + 1 in size
wire [BITS - 1 : 0] proxy = product[0] ? multiplicand : 0;
wire [BITS : 0] sum = product[BITS * 2 - 1 : BITS] + proxy; // NB. N
+ 1 bits
always @(posedge clock) begin
// $write("%b %b %b %d %b\n", clock, reset, finished, counter,
product);
if (reset == 1'b1) begin
multiplicand <= input_a;
product <= { 1'b0, input_b }; // Zero extend input_b
counter <= BITS;
finished <= 0;
end
else if (counter != 0) begin
product <= { sum, product[BITS - 1 : 1] }; // Add and shift
counter <= counter - 1;
end
else /* Counter is zero */ begin
finished <= 1;
end
end
endmodule
That's it. Hit me!
James