1 Verilog – System Design Example Example: Design a 4-bit by 4-bit Multiplier using Repetitive Add Algorithm. For example, if you wanted to multiply 1010 A 0110 B ------00111100 Result The above can be accomplished by repeatedly adding 1010 six times (i.e., the B value). The datapath and the controller for this will appear as: A (4 bits) Clk A (4 bit Latch) B(4 bits) 4 bit down Counter Load A Load Counter Dec. Count 0 NOR 4 8-Bit Adder CountEq0 Ready Reset Result (8-bit FET Register) Done Load Result Clear Result : Controller State Diagram: ______ Ready Load A Load Counter Clear Result ________ Ready CountEq0 Load Result CountEq0 Done _______ = CountEq0 C O N T R O L L E R 2 Create a new Altera project called MultiplierRepetitiveAdd by using the new project wizard. The different steps of the wizard are as shown below. 3 Depending upon the complexity of the project, you can choose an appropriate device family. 4 Select Verilog HDL when prompted for EDA Tool settings as shown below. 5 Choose File->New and select the Verilog HDL option, Type the following code in the editor window. module OneBitAdder(a,b,cin,sum,cout); input a,b,cin; output sum,cout; assign sum = a ^ b ^ cin; assign cout = (a & b) | (a & cin) | (b & cin); endmodule Save the file in the MultiplierRepetitiveAdd folder with the name of OneBitAdder.v. 6 Similarly add another file to the project with the following code and save it as EightBitAdder.v. module EightBitAdder(A, B, cin, Sum, cout); input[7:0] A,B; input cin; output[7:0] Sum; output cout; wire[7:0] ctemp; OneBitAdder add0(A[0],B[0],cin,Sum[0],ctemp[0]); OneBitAdder add1(A[1],B[1],ctemp[0],Sum[1],ctemp[1]); OneBitAdder add2(A[2],B[2],ctemp[1],Sum[2],ctemp[2]); OneBitAdder add3(A[3],B[3],ctemp[2],Sum[3],ctemp[3]); OneBitAdder add4(A[4],B[4],ctemp[3],Sum[4],ctemp[4]); OneBitAdder add5(A[5],B[5],ctemp[4],Sum[5],ctemp[5]); OneBitAdder add6(A[6],B[6],ctemp[5],Sum[6],ctemp[6]); OneBitAdder add7(A[7],B[7],ctemp[6],Sum[7],ctemp[7]); endmodule As you can see from the above code that the 8-bit adder uses 8 one-bit adder modules to form a ripple carry adder. Similarly create and save the following modules. module Reg4Latch(D,clk,Q); // save as Reg4Latch.v input[3:0] D; input clk; output[3:0] Q; //reg[3:0] temp; // rather than declaring reg[3:0] temp, you can declar reg Q[3:0] reg[3:0]Q; // and assign D to Q always @(clk,D) // latch begin if (clk == 1'b1) Q = D; //temp = D; end //assign Q = temp; endmodule module Reg8FF(D,clk,clear,Q); // save as Reg8FF.v input[7:0] D; input clk,clear; output[7:0] Q; reg[7:0] temp; always @(negedge clk) // Falling edge triggered begin if (clear == 1'b1) temp = 8'b00000000; else temp = D; 7 end assign Q = temp; endmodule module NORG4(X,out); // save as NORG4.v input[3:0] X; output out; assign out = ~(X[0]| X[1] | X[2] | X[3]); endmodule module DownCounter4(Data,clk,load,dec,Out); // save as DownCounter4.v input[3:0] Data; input load, dec, clk; output[3:0] Out; reg[3:0] temp; always @(negedge clk) begin if (load == 1'b1) temp = Data; else begin if (dec == 1'b1) temp = temp - 1'b1; end end assign Out = temp; endmodule module Controller(ready,reset,counteq0,clk,loadA,loadCounter,decCount,clearResult, loadResult,done,state); // save as Controller.v input ready,reset,counteq0,clk; output loadA,loadCounter,clearResult,decCount,loadResult,done; output[1:0] state; reg loadA,loadCounter,clearResult,loadResult,decCount,done; // same outputs can be declared as reg reg[1:0] stateT; parameter s0=0, s1 = 1, s2 = 2; always @(negedge clk) begin if (reset == 1'b1) stateT = s0; else case(stateT) s0 : if (ready == 1'b0) stateT = s0; 8 else stateT = s1; s1 : if (counteq0 == 1'b0) stateT = s1; else stateT = s2; s2 : stateT = s0; endcase end assign state = stateT; always @(stateT,clk,counteq0) // important parameters for sensitivity list begin case(stateT) s0 : begin loadA = 1'b1; loadCounter = 1'b1; clearResult = 1'b1; loadResult = 1'b0; decCount = 1'b0; done = 1'b0; end s1 : begin loadA = 1'b0; loadCounter = 1'b0; clearResult = 1'b0; loadResult = ~counteq0 & clk; // without anding with clk, loadResult will decCount = 1'b1; // will be high in multiple states done = 1'b0; end s2 : begin loadA = 1'b0; loadCounter = 1'b0; clearResult = 1'b0; loadResult = 1'b0; decCount = 1'b0; done = 1'b1; end endcase end endmodule module DataPath(A, B, clk,ready,Prod,decCounter,loadCounter,loadA, clearResult,loadResult, counteq0,count); // save as DataPath.v input[3:0] A,B; input clk,ready,decCounter,loadCounter,loadA,clearResult,loadResult; output[7:0] Prod; output counteq0; output[3:0] count; 9 reg temp[7:0]; wire[3:0] CounterOut; wire[7:0] AdderOut; wire[3:0] Aout; wire cout; wire[7:0] ResultOut; //-----------datapth components--------------Reg4Latch AReg(A,loadA,Aout); EightBitAdder add8({4'b0000,A},ResultOut,1'b0,AdderOut,cout); Reg8FF res8(AdderOut,loadResult,clearResult,ResultOut); DownCounter4 counter4(B,clk,loadCounter,decCounter,CounterOut);// parameters for Reg8FF: Data,clk,load,dec,Out NORG4 n4(CounterOut,counteq0); //-------------------------------------------assign Prod = ResultOut; assign count=CounterOut; // for debugging purpose endmodule module MultiplierRepetitiveAdd(A,B,ready,reset,clk,Result,done,state,count,loadResult); // save as MultiplierRepetitiveAdd.v input[3:0] A,B; // state, count, loadResult outputs are for debugging purpose input ready,reset,clk; output[7:0] Result; output[3:0] count; output loadResult; output done; wire[7:0] tempRes; output[1:0] state; wire[1:0] stateTemp; wire[3:0] countTemp; wire decCounter,loadCounter,loadA,clearResult,loadResultT,doneTemp,counteq0; DataPath dpath(A, B, clk,ready,tempRes,decCounter,loadCounter,loadA,clearResult,loadResultT, counteq0,countTemp); Controller control(ready,reset,counteq0,clk,loadA,loadCounter,decCounter,clearResult,loadResultT,doneT emp,stateTemp); assign Result = tempRes; assign done = doneTemp; assign state = stateTemp; assign count = countTemp; // for debugging purpose assign loadResult=loadResultT; // for debugging purpose endmodule Add another Verilog file for testbench to the project by choosing File->new. Type the following code in it. 10 // testbench `timescale 1ns/100ps module tbMultiplierRepetitiveAdd(); // save as tbMultiplierRepetitiveAdd.v reg[3:0] At,Bt; reg readyt,resett,clkt; wire[7:0] Result; wire done; wire[1:0] state; // inputs to module are declared as reg, outputs as wire in TB wire[3:0] count; wire loadResult; MultiplierRepetitiveAdd mrp(At,Bt,readyt,resett,clkt,Result,done,state,count,loadResult); initial begin clkt = 1'b0; resett = 1'b1; #15 resett = 1'b0; end initial begin readyt = 1'b0; #30 readyt = 1'b1; #20 readyt = 1'b0; end initial begin At = 4'b1010; Bt = 4'b0110; end always begin #5 clkt = ~clkt; end initial #200 $finish; endmodule From the Assignments->Settings menu, click on the TestBenches… button as shown below. 11 Then click on the New button: Then type the name of the testbench file i.e., tbMultiplierRepetitiveAdd.v as shown below. After selecting the testbench file, click on the Add button as shown above. 12 Click on the OK button, then OK button in the next dialog. Then click on Apply and OK. 13 Now the testbench will be compiled along with rest of the Verilog code for the project. From the Processing menu, choose “Start Compilation”. 14 If there are no errors reported, you can simulate your project by choosing Tools->Run Simulation Tool ->RTL Simulation as shown below. This will launch the ModelSim and run the project to end of simulation time. When it prompts you to “Are you sure you want to finish?”, choose “NO”. Then right click in the waveform area and choose “Zoom full” as shown below. 15 This will show the complete simulation for your design as shown below.