//*************************************************************************************** // 6.371 Design Project //--------------------------------------------------------------------------------------- // Christopher Batten // September 27, 2002 // // A behavioral model of the counter datapath and associated driver module. The // driver module causes the counter to increment to a value and then decrement // back to the original value in an infinite loop // `include "/home/cad/tsmc/18/artisan/sc/verilog/tsmc18.v" `timescale 1ns/10ps //--------------------------------------------------------------------------------------- // Constants //--------------------------------------------------------------------------------------- `define DATABUS 31:0 `define BUSWIDTH 32 `define COMPREG 32'hF `define ADDREG 32'h0 //--------------------------------------------------------------------------------------- // Behavioral model of counter unit //--------------------------------------------------------------------------------------- module incdec( clk, reset, datain, add_selA_0_, add_selA_1_, add_selB_0_, add_selB_1_, add_reg_en, comp_reg_en, cin, cout, neq ); input clk; // Clock signal input reset; // Active-low reset input [`DATABUS] datain; // Data bus for loading initial values input add_selA_0_; // 00=true, 01=complement, 10,11=zero input add_selA_1_; // input add_selB_0_; // 00=datain, 01=bypass, 10,11=zero input add_selB_1_; // input add_reg_en; // Active-high enable input comp_reg_en; // Active-high enable input cin; // Set to one for decrement output cout; // Can check for counter overflow output neq; // reg [`DATABUS] add_reg_out; reg [`DATABUS] comp_reg_out; wire [`DATABUS] addA; wire [`DATABUS] addB; wire [`DATABUS] incdec_const; reg [`DATABUS] add_out; reg cout; wire [1:0] add_selA = { add_selA_1_, add_selA_0_ }; wire [1:0] add_selB = { add_selB_1_, add_selB_0_ }; // Constant assign incdec_const = 32'd1; // Muxes assign addA = (add_selA == 2'd0) ? incdec_const : (add_selA == 2'd1) ? ~incdec_const : (add_selA == 2'd2) ? 0 : 0; assign addB = (add_selB == 2'd0) ? datain : (add_selB == 2'd1) ? add_reg_out : (add_selB == 2'd2) ? 0 : 0; // Adder always @(addA or addB or cin) begin: ripple integer i; // FOR loop index, not in hardware reg cinl,p,g; // expanded at compile time into many signals cinl = cin; for (i = 0; i < `BUSWIDTH; i = i + 1) begin p = addA[i] ^ addB[i]; // carry propagate g = addA[i] & addB[i]; // carry generate add_out[i] = p ^ cinl; cinl = g | (p & cinl); // carry into next stage end cout = cinl; end // block: ripple // Comparator assign neq = (comp_reg_out == add_out) ? 0 : 1; // Clock in registers if enabled always @(posedge clk) begin: clkregs if (~reset) begin add_reg_out <= 0; comp_reg_out <= 0; end else begin if (comp_reg_en) comp_reg_out <= datain; if (add_reg_en) add_reg_out <= add_out; end end endmodule //--------------------------------------------------------------------------------------- // Driver FSM //--------------------------------------------------------------------------------------- module control(clk,reset,dataout,add_selA,add_selB,add_reg_en,comp_reg_en,cin,neq); output [`DATABUS] dataout; output [1:0] add_selA; output [1:0] add_selB; output add_reg_en; output comp_reg_en; output cin; input neq; input clk; input reset; reg [`DATABUS] dataout; reg [1:0] add_selA; reg [1:0] add_selB; reg add_reg_en; reg comp_reg_en; reg cin; reg [2:0] state; reg [2:0] next_state; always @(state or neq) begin case (state) // State0: Load comparator register 3'd0: begin dataout = `COMPREG; add_selA = 2'b11; add_selB = 2'b11; add_reg_en = 0; comp_reg_en = 1; cin = 0; next_state = 3'd1; end // State1: Load accumulate register 3'd1: begin dataout = `ADDREG; add_selA = 2'b11; add_selB = 2'b00; add_reg_en = 1; comp_reg_en = 0; cin = 0; next_state = 3'd2; end // State2: Enable bypass loop using muxes 3'd2: begin dataout = `ADDREG; add_selA = 2'b00; add_selB = 2'b01; add_reg_en = 1; comp_reg_en = 0; cin = 0; next_state = (~neq) ? 3'd3 : 3'd2; end // State3: Load the original accumulate value into comparator register 3'd3: begin dataout = `ADDREG; add_selA = 2'b11; add_selB = 2'b11; add_reg_en = 0; comp_reg_en = 1; cin = 0; next_state = 3'd4; end // State4: Load the original comparator value into accumulate register 3'd4: begin dataout = `COMPREG; add_selA = 2'b11; add_selB = 2'b00; add_reg_en = 1; comp_reg_en = 0; cin = 0; next_state = 3'd5; end // State5: Enable bypass mux and decrement function 3'd5: begin dataout = `ADDREG; add_selA = 2'b01; add_selB = 2'b01; add_reg_en = 1; comp_reg_en = 0; cin = 1; next_state = (~neq) ? 3'd0 : 3'd5; end // Default: Go to state zero default: begin dataout = `ADDREG; add_selA = 2'b11; add_selB = 2'b11; add_reg_en = 0; comp_reg_en = 0; cin = 0; next_state = 3'd0; end endcase end // always @ (state) always @(posedge clk) begin if (~reset) #1 state <= 3'd0; else #1 state <= next_state; end endmodule //--------------------------------------------------------------------------------------- // Main module //--------------------------------------------------------------------------------------- // We should always use named argument lists when instantiating the primary module // under test since there are no guarentees on the argument order generated // by spongepaint for the functional model. module main; reg clk; reg reset; wire [`DATABUS] datain; wire [1:0] add_selA; wire [1:0] add_selB; wire add_reg_en; wire comp_reg_en; wire cin; wire cout; wire neq; control xcontrol(clk,reset,datain,add_selA,add_selB,add_reg_en,comp_reg_en,cin,neq); incdec xincdec( .clk(clk), .reset(reset), .datain(datain), .add_selA_1_(add_selA[1]), .add_selA_0_(add_selA[0]), .add_selB_1_(add_selB[1]), .add_selB_0_(add_selB[0]), .add_reg_en(add_reg_en), .comp_reg_en(comp_reg_en), .cin(cin), .cout(cout), .neq(neq)); initial begin $dumpfile("verilog_test.vcd"); $dumpvars; clk = 0; reset = 0; #7 reset = 1; #500 $finish; end always #5 clk = ~clk; endmodule