////////////////////////////////////////////////////////////////////////////////
///
/// Solution to LSU EE 3755 Spring 2002 Homework 4
///
////////////////////////////////////////////////////////////////////////////////
/// Problem 1
///
// Complete the module below so that it performs 18 bit x 9 bit
// unsigned integer multiplication using a radix-8 multiplier using
// the same handshaking as mult_18x9_sim (and other modules presented
// in class).
//
// Hint: The solution is a straightforward extension of imult_ord_radix_4
// in l07 http://www.ece.lsu.edu/ee3755/2002/l07.html) to radix 8.
module mult_radix_8(prod,ready,cand,multiplier,start,clk);
input [17:0] cand;
input [8:0] multiplier;
input start, clk;
output prod;
output ready;
reg [29:0] product;
wire [26:0] prod = product[26:0];
reg [1:0] bit;
wire ready = !bit;
initial bit = 0;
wire [18:0] candx2 = cand << 1;
wire [19:0] candx3 = candx2 + cand;
wire [19:0] candx4 = cand << 2;
wire [20:0] candx5 = candx4 + cand;
wire [20:0] candx6 = candx4 + candx2;
wire [20:0] candx7 = candx6 + cand;
always @( posedge clk )
if( ready && start ) begin
bit = 3;
product = { 19'd0, multiplier };
end else if( bit ) begin
case ( product[2:0] )
3'b000: product[29:9] = product[29:9];
3'b001: product[29:9] = product[29:9] + cand;
3'b010: product[29:9] = product[29:9] + candx2;
3'b011: product[29:9] = product[29:9] + candx3;
3'b100: product[29:9] = product[29:9] + candx4;
3'b101: product[29:9] = product[29:9] + candx5;
3'b110: product[29:9] = product[29:9] + candx6;
3'b111: product[29:9] = product[29:9] + candx7;
endcase
product = product >> 3;
bit = bit - 1;
end
endmodule
////////////////////////////////////////////////////////////////////////////////
/// Problem 2
///
// Complete the module below so that it performs a 18 x 18 bit
// unsigned integer multiplication using two mult_prob_2 18 x 9 bit
// multiplier modules. All modules use the same handshaking.
module mult_faster(prod,ready,cand,multiplier,start,clk);
input [17:0] cand;
input [17:0] multiplier;
input start, clk;
output [35:0] prod;
output ready;
wire [26:0] prod_lo, prod_hi;
wire rdy_1;
mult_prob_2 m1(prod_lo,rdy_1,cand,multiplier[8:0], start,clk);
mult_prob_2 m2(prod_hi,ready,cand,multiplier[17:9],start,clk);
assign prod = prod_lo + ( prod_hi << 9 );
endmodule
////////////////////////////////////////////////////////////////////////////////
/// Problem 3
///
// Complete the module below so that it performs a 18 x 18 bit
// unsigned integer multiplication using one mult_prob_3 18 x 9 bit
// multiplier module. All modules use the same handshaking.
//
// Hint: Use a state machine to control the two modules.
module mult_cheaper(prod,ready,cand,multiplier,start,clk);
input [17:0] cand;
input [17:0] multiplier;
input start, clk;
output [35:0] prod;
output ready;
parameter ST_rdy = 3'd0;
parameter ST_m1_rdy = 3'd1;
parameter ST_m1_cmp = 3'd2;
parameter ST_m2_rdy = 3'd4;
parameter ST_m2_cmp = 3'd5;
reg [2:0] state;
wire [8:0] lier = state[2] ? multiplier[17:9] : multiplier[8:0];
reg [26:0] first_prod;
wire [26:0] prod_m;
wire ready_m;
reg start_m;
mult_prob_3 m(prod_m,ready_m,cand,lier,start_m,clk);
assign ready = state == ST_rdy;
assign prod = first_prod + ( prod_m << 9 );
always @( state or start )
case( state )
ST_rdy : start_m = start;
ST_m1_rdy, ST_m2_rdy : start_m = 1;
default : start_m = 0;
endcase
always @( posedge clk )
case( state )
ST_rdy : if( start ) state = ST_m1_rdy;
ST_m1_rdy : if( ~ready_m ) state = ST_m1_cmp;
ST_m1_cmp : if( ready_m ) begin first_prod=prod_m; state=ST_m2_rdy; end
ST_m2_rdy : if( ~ready_m ) state = ST_m2_cmp;
ST_m2_cmp : if( ready_m ) state = ST_rdy;
default : if( ready_m ) state = ST_rdy;
endcase
endmodule
// exemplar translate_off
module mult_prob_2(prod,ready,cand,multiplier,start,clk);
input [17:0] cand;
input [8:0] multiplier;
input start, clk;
output [26:0] prod;
output ready;
mult_18x9_sim #(0) the_worlds_mult(prod,ready,cand,multiplier,start,clk);
endmodule
module mult_prob_3(prod,ready,cand,multiplier,start,clk);
input [17:0] cand;
input [8:0] multiplier;
input start, clk;
output [26:0] prod;
output ready;
mult_18x9_sim #(1) the_worlds_mult(prod,ready,cand,multiplier,start,clk);
endmodule
module mult_18x9_sim(prod,ready,cand,multiplier,start,clk);
input [17:0] cand;
input [8:0] multiplier;
input start, clk;
output [26:0] prod;
output ready;
parameter random_delay = 0;
reg [26:0] prod;
reg [3:0] bit; // Not necessarily size needed for other modules.
wire ready = !bit;
initial bit <= 0;
always @( posedge clk )
if( ready && start ) begin
bit <= random_delay ? 1 + $random : 3;
end else if( bit ) begin
bit <= bit - 1;
if( bit == 1 ) prod <= cand * multiplier;
end
endmodule
module test_faster();
testmults #(0) tm();
endmodule
module test_cheaper();
testmults #(1) tm();
endmodule
module test_8();
testmults #(2) tm();
endmodule
module testmults();
parameter DUT = 0;
parameter stop_on_error = 1;
parameter DUT_faster = 0;
parameter DUT_cheaper = 1;
parameter DUT_eight = 2;
reg [35:0] product;
wire [35:0] product_c, product_f;
wire [26:0] product_8;
wire ready_c, ready_f, ready_8;
reg ready;
reg [17:0] multiplier;
reg [17:0] multiplicand;
reg start, clk;
reg [35:0] shadow_product;
integer i;
always @( product_c or product_f or product_8
or ready_c or ready_f or ready_8 )
case( DUT )
DUT_faster: begin product = product_f; ready = ready_f; end
DUT_cheaper: begin product = product_c; ready = ready_c; end
DUT_eight: begin product = product_8; ready = ready_8; end
endcase
mult_radix_8 m8(product_8,ready_8,multiplicand,multiplier[8:0],start,clk);
mult_cheaper mc(product_c,ready_c,multiplicand,multiplier,start,clk);
mult_faster mf(product_f,ready_f,multiplicand,multiplier,start,clk);
always #10 clk = !clk;
real cycles;
initial begin cycles = 0; forever @( posedge clk ) cycles <= cycles + 1; end
reg [17:0] lier_mask;
reg [7*8-1:0] name;
real start_time;
real cpm;
integer err;
initial begin
case( DUT )
DUT_faster: begin lier_mask = 18'o777777; name = "Faster"; end
DUT_cheaper: begin lier_mask = 18'o777777; name = "Cheaper"; end
DUT_eight: begin lier_mask = 18'o000777; name = "Radix 8"; end
endcase
clk = 0;
start = 0;
err = 0;
#25;
start_time = cycles;
$display("Starting test for %s",name);
for(i=0; i<1000; i=i+1) begin
wait( ready );
#5;
multiplier = $random & lier_mask;
multiplicand = $random & 18'o777777;
shadow_product = multiplier * multiplicand;
#1;
start = 1;
wait( !ready );
start = 0;
wait( ready );
#1;
if( shadow_product !== product ) begin
$display("FAIL: %s %o x %o = %o(correct) != %o\n",
name,
multiplier, multiplicand,
shadow_product, product );
err = err + 1;
if( stop_on_error && err >= stop_on_error ) $stop;
end
end
cpm = (cycles - start_time) / ( i ? i : 1 );
$display("Finished at speed of %f cycles per multiplication.", cpm);
case ( DUT )
DUT_faster:
if( cpm > 5.1 ) begin
$display("FAIL: Faster multiplier taking too long.");
err = err + 1;
end else if ( cpm < 3.0 ) begin
$display("FAIL: Faster multiplier too fast.");
err = err + 1;
end
DUT_eight:
if( cpm > 4.1 ) begin
$display("FAIL: Radix 8 multiplier taking too long.");
err = err + 1;
end else if ( cpm < 3.0 ) begin
$display("FAIL: Radix 8 multiplier too fast.");
err = err + 1;
end
DUT_cheaper:
if( cpm > 22 ) begin
$display("FAIL: Cheaper multiplier taking too long.");
err = err + 1;
end else if ( cpm < 15 ) begin
$display("FAIL: Cheaper multiplier too fast.");
err = err + 1;
end
endcase
if( err )
$display("FAIL: %s, encountered %d errors.",name,err);
else
$display("PASS: %s, no errors found.",name);
$display("Done with tests.");
$stop;
end
endmodule
// exemplar translate_on