| // |
| // Copyright (c) 1999 Thomas Coonan (tcoonan@mindspring.com) |
| // |
| // This source code is free software; you can redistribute it |
| // and/or modify it in source code form under the terms of the GNU |
| // General Public License as published by the Free Software |
| // Foundation; either version 2 of the License, or (at your option) |
| // any later version. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
| // |
| // **** Here's a simple, sequential multiplier. Very simple, unsigned.. |
| // Not very well tested, play with testbench, use at your own risk, blah blah blah.. |
| // |
| |
| // |
| // Unsigned 16-bit multiply (multiply two 16-bit inputs to get a 32-bit output) |
| // |
| // Present data and assert start synchronous with clk. |
| // Assert start for ONLY one cycle. |
| // Wait N cycles for answer (at most). Answer will remain stable until next start. |
| // You may use DONE signal as handshake. |
| // |
| // Written by tom coonan |
| // |
| module mult16 (clk, resetb, start, done, ain, bin, yout); |
| parameter N = 16; |
| input clk; |
| input resetb; |
| input start; // Register the ain and bin inputs (they can change afterwards) |
| //input [N-1:0] ain; |
| //input [N-1:0] bin; |
| //output [2*N-1:0] yout; |
| input [15:0] ain; |
| input [15:0] bin; |
| output [31:0] yout; |
| |
| output done; |
| |
| //reg [2*N-1:0] a; |
| //reg [N-1:0] b; |
| //reg [2*N-1:0] yout; |
| reg [31:0] a; |
| reg [15:0] b; |
| reg [31:0] yout; |
| |
| reg done; |
| |
| always @(posedge clk or negedge resetb) begin |
| if (~resetb) begin |
| a <= 0; |
| b <= 0; |
| yout <= 0; |
| done <= 1'b1; |
| end |
| else begin |
| // Load will register the input and clear the counter. |
| if (start) begin |
| a <= ain; |
| b <= bin; |
| yout <= 0; |
| done <= 0; |
| end |
| else begin |
| // Go until b is zero |
| if (~done) begin |
| if (b != 0) begin |
| // If '1' then add a to sum |
| if (b[0]) begin |
| yout <= yout + a; |
| end |
| b <= b >> 1; |
| a <= a << 1; |
| $display ("a = %h, b = %h, yout = %h", a,b,yout); |
| end |
| else begin |
| done <= 1'b1; |
| end |
| end |
| end |
| end |
| end |
| endmodule |
| |
| |
| module mul16; |
| reg clk, resetb, start; |
| reg [15:0] a; |
| reg [15:0] b; |
| wire [31:0] y; |
| wire done; |
| |
| mult16 mult16inst (clk, resetb, start, done, a, b, y); |
| |
| initial begin |
| clk = 0; |
| forever begin |
| #10 clk = ~clk; |
| end |
| end |
| |
| initial begin |
| resetb = 0; |
| #30 resetb = 1; |
| end |
| |
| integer num_errors; |
| parameter MAX_TRIALS = 10; |
| |
| initial begin |
| $dumpfile ("multdiv.vcd"); |
| $dumpvars (0,a); |
| $dumpvars (0,b); |
| $dumpvars (0,y); |
| $dumpvars (0,resetb); |
| $dumpvars (0,done); |
| num_errors = 0; |
| |
| #100; |
| |
| // Do a bunch of random multiplies |
| repeat (MAX_TRIALS) begin |
| test_multiply ($random, $random); |
| end |
| |
| // Special cases |
| test_multiply ($random, 1); |
| test_multiply (1, $random); |
| test_multiply ($random, 0); |
| test_multiply (0, $random); |
| |
| $display ("Done. %0d Errors", num_errors); |
| if(num_errors == 0) |
| $display("PASSED"); |
| #800; |
| $finish; |
| end |
| |
| task test_multiply; |
| input [15:0] aarg; |
| input [15:0] barg; |
| |
| integer expected_answer; |
| |
| begin |
| if (~done) begin |
| $display ("Multiplier is Busy!!"); |
| end |
| else begin |
| @(negedge clk); |
| start = 1; |
| a = aarg; |
| b = barg; |
| @(negedge clk) start = 0; |
| @(posedge done); |
| expected_answer = a*b; |
| $display ("%0d * %0d = %0h, Reality = %0h", a, b, y, expected_answer); |
| if (y !== expected_answer) begin |
| $display (" FAILED!"); |
| num_errors = num_errors + 1; |
| end |
| end |
| end |
| endtask |
| |
| endmodule |
| |