//////////////////////////////////////////////////////////////////////////////// /// /// 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