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