////////////////////////////////////////////////////////////////////////////////
///
/// Template for LSU EE 3755 Spring 2002 Homework 4
///
/// Due: Monday, 25 March 2002
/// Name:
/// Instructions:
//
// Copy this to a file named hw04.v to directory ~/hw in your
// class account. (~ is your home directory.) Use this
// file for your solution. Your entire solution should be in
// this file.
//
// Do not rename the modules in this file and be sure to use the
// directory and filename given above.
// Local copy of this file:
// /home/classes/ee3755/com/v/hw04.v
//
// Instruction on Simulator, Emacs, etc:
// http://www.ece.lsu.edu/ee3755/proc.html
//
// Documentation for Simulator, Unix, etc.
// http://www.ece.lsu.edu/ee3755/ref.html
// See problems below for further instructions.
// Warning: Problem 3 is more difficult than 1 and 2.
/// Grading Criteria
//
// Passes the testbench.
// If it fails, partial credit will be given based on the type of
// problem. A large amount of credit will be deducted for
// compilation errors.
//
// Follows the guidelines.
// Be sure to instantiate the correct number of modules per module.
//
// Coded cleanly.
// Points will be deducted for code that is correct but much more
// complex, unreadable, or inefficient than it has to be.
// For example, points would be deducted for the second assign below.
`ifdef XXX
assign x = a & b; // Use assign on this line instead of one on line below.
assign x = a == 1'b1 ? ( b == 1'b1 ? 1'b1 : 1'b0 ) : ( b == 1'b1 ? 1'b0 : 1'b0 );
`endif
////////////////////////////////////////////////////////////////////////////////
/// 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 from l07
// http://www.ece.lsu.edu/ee3755/2002/l07.html, also further down in
// this file) 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 [26:0] prod;
output ready;
/// Implement a 18 x 9 unsigned integer multiplier
//
// [ ] Can use structural and synthesizable behavioral code.
// [ ] Do not instantiate other modules.
// [ ] Solution can use the addition operator.
// [ ] Solution CANNOT use the multiplication operator.
// [ ] Test using module test_8.
//
// Can be solved by adding 8 lines to imult_ord_radix_4 (in this
// file) and modifying several other lines.
endmodule
////////////////////////////////////////////////////////////////////////////////
/// Problem 2
///
// Complete the module below so that it performs an 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;
// Implement an 18 x 18 bit multiplier using two 18 x 9 bit multipliers.
//
// [ ] Instantiate TWO mult_prob_2 modules.
// [ ] Can use structural and synthesizable procedural code.
// [ ] Can use + operator, and can assume addition is very fast.
// [ ] The two 18 x 9 bit multipliers must work simultaneously.
// [ ] Assume that the two multipliers take the same amount of time.
// [ ] Test using test_faster.
//
// Can be solved with just one line of code, plus declarations.
endmodule
////////////////////////////////////////////////////////////////////////////////
/// Problem 3
///
// Complete the module below so that it performs an 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 instantiated multiplier.
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;
// Implement an 18 x 18 bit multiplier using one 18 x 9 bit multiplier.
//
// [ ] Instantiate ONE mult_prob_3 module.
// [ ] Do not assume that mult_prob_3 takes a fixed amount of time.
// [ ] Can use structural and synthesizable procedural code.
// [ ] Can use + operator, and can assume addition is very fast.
// [ ] Test using test_cheaper.
//
// A straightforward solution uses 18 lines of code, plus declarations.
endmodule
////////////////////////////////////////////////////////////////////////////////
/// Radix-4 Multiplication Module
///
// The solution to Problem 1 above can be based on the module below.
module imult_ord_radix_4(prod,ready,multiplicand,multiplier,start,clk);
input [15:0] multiplicand, multiplier;
input start, clk;
output prod;
output ready;
reg [32:0] product;
wire [31:0] prod = product[31:0];
reg [4:0] bit;
wire ready = !bit;
reg [17:0] pp;
initial bit = 0;
wire [17:0] multiplicand_X_1 = {1'b0,multiplicand};
wire [17:0] multiplicand_X_2 = {multiplicand,1'b0};
wire [17:0] multiplicand_X_3 = multiplicand_X_2 + multiplicand_X_1;
always @( posedge clk )
if( ready && start ) begin
bit = 8;
product = { 16'd0, multiplier };
end else if( bit ) begin
case ( {product[1:0]} )
2'd0: pp = {2'b0, product[31:16] };
2'd1: pp = {2'b0, product[31:16] } + multiplicand_X_1;
2'd2: pp = {2'b0, product[31:16] } + multiplicand_X_2;
2'd3: pp = {2'b0, product[31:16] } + multiplicand_X_3;
endcase
product = { pp, product[15:2] };
bit = bit - 1;
end
endmodule
////////////////////////////////////////////////////////////////////////////////
/// Modules Instantiated In Solutions
///
// 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
////////////////////////////////////////////////////////////////////////////////
/// Testbench Code
///
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