Design a State machine and write the Verilog code for a Calculator. The Calculator is a sequential circuit capable of performing 4 operations – Addition, Subtraction, Multiplication and Division based on the inputs provided.
• The clock signal is given by clk
• It has a 2 bit Control input, ctrl that decides
• the type of Operation to be performed
• It has two 32 bit Data inputs, namely A & B
• and one 32 bit Data output C
• The reset signal is used to reset the circuit
• It works on DVS (Data-Valid-Stall) protocol
The Data Valid Stall Protocol for a single data is shown below.
The data is accepted only when the Valid signal is asserted and Stall is deasserted. In the next cycle, the Valid is deasserted.
module calc (
input [7:0] inpA ,
input [7:0] inpB ,
input [01:0] inpOpType ,
output[15:0] outC ,
input iValid ,
output iStall ,
input oStall ,
output oValid ,
input clk ,
input rstn
) ;
//----------------------------------------------------------------------
parameter ST_IDL = 1'b0 ;
parameter ST_STALL = 1'b1 ;
reg inp_dstall_r, oup_dval_r, lat_inp_r ;
reg inp_dstall_s, oup_dval_s, lat_inp_s ;
reg st_cur, st_nxt ;
reg [31:0] store_a, store_b, oup_s ;
reg [01:0] store_ctrl ;
//----------------------------------------------------------------------
// This is where the FSM code should go
//----------------------------------------------------------------------
parameter s0=2'b00, s1=2'b01, s2=2'b10, s3=2'b11;
reg[1:0] cs,ns;
always@(posedge clk)
begin
if(rstn)
cs<=s0;
else
cs<=ns;
end
//----------------------------------------------------------------------
always @(posedge clk or negedge rstn) begin
if(!rstn) begin
lat_inp_r <= 1'b0 ;
inp_dstall_r <= 1'b0 ;
st_cur <= ST_IDL ;
oup_dval_r <= 1'b0 ;
end
else begin
inp_dstall_r <= inp_dstall_s ;
lat_inp_r <= lat_inp_s ;
st_cur <= st_nxt ;
oup_dval_r <= oup_dval_s ;
end
end
//----------------------------------------------------------------------
always @(posedge clk or negedge rstn) begin
ns=s0;
case(cs)
s0:if(!store_ctrl)ns=s1;
s1:if(store_ctrl) ns=s2;
else ns=s1;
s2: if(store_ctrl)ns=s3;
else ns=s1;
s3: if(!store_ctrl) ns=s1;
endcase
end
always @(posedge clk) begin
if(lat_inp_s) begin
store_a <= inpA ;
store_b <= inpB ;
store_ctrl <= inpOpType ;
end
end
//----------------------------------------------------------------------
always @* begin
if(store_ctrl == 2'b00) oup_s = store_a + store_b ;
else if(store_ctrl == 2'b01) oup_s = store_a - store_b ;
else if(store_ctrl == 2'b10) oup_s = store_a * store_b ;
else if(store_b == 0) oup_s = 0 ;
else oup_s = store_a / store_b ;
end
//----------------------------------------------------------------------
assign iStall = inp_dstall_r ;
assign oValid = oup_dval_r ;
assign outC = oup_s ;
//----------------------------------------------------------------------
endmodule
Testbench
module tb_top;
parameter CYCLE = 10;
reg clock;
reg rstn;
reg iValid;
reg [7:0] A;
reg [7:0] B;
reg [1:0] ctrl;
reg [15:0] gotC, outC;
// DUT Initialization
calc DUT(
.inpA (A),
.inpB (B),
.inpOpType (ctrl),
.outC (outC),
.iValid (iValid),
.iStall (),
.oStall (1'b0),
.oValid (oValid),
.clk (clock),
.rstn (rstn));
//----------------------------------------------------------------------------------
// Clock generation
//----------------------------------------------------------------------------------
initial begin
clock = 1'b0;
forever
#(CYCLE/2) clock = ~clock;
end
//----------------------------------------------------------------------------------
// Body
//----------------------------------------------------------------------------------
initial begin
init_signals();
reset_dut();
calc_read_write(8'h5, 8'h5, 2'b00);
calc_read_write(8'h8, 8'h5, 2'b01);
calc_read_write(8'h7, 8'h11, 2'b10);
calc_read_write(8'h16, 8'h2, 2'b11);
$finish;
end
//----------------------------------------------------------------------------------
// Calci Read Write Method
//----------------------------------------------------------------------------------
task calc_read_write;
input [7:0] inpA;
input [7:0] inpB;
input [1:0] inpCtrl;
reg [15:0] expC;
$display("Inside Calculator Read Write task...");
$display("Inputs : A = %h B = %h ctrl = %b", inpA, inpB, inpCtrl);
// Expected Output calculation
case (inpCtrl)
2'b00: expC = inpA + inpB;
2'b01: expC = inpA - inpB;
2'b10: expC = inpA * inpB;
2'b11: if (inpB == 0) expC = 0;
else expC = inpA / inpB;
endcase // case(inpCtrl)
// Driving Inputs
@(posedge clock);
A = inpA;
B = inpB;
ctrl = inpCtrl;
iValid = 'b1;
// Sampling Outputs
wait(oValid);
@(posedge clock);
gotC = outC;
iValid = 0;
// Comparing Expected and Actual Output
$display("Output : Expected = %h Actual = %h", expC, gotC);
if (gotC == expC)
$display("PASS: A = %h B = %h C = %h type = %b\n", inpA, inpB, gotC, inpCtrl);
else
$display("FAIL: A = %h B = %h C = %h type = %b\n", inpA, inpB, gotC, inpCtrl);
wait(!oValid);
endtask // calc_read_write
//----------------------------------------------------------------------------------
// Initialize Input signals
//----------------------------------------------------------------------------------
task init_signals;
begin
$display("Initializing Input signals...");
rstn = 'b1;
A = 'b0;
B = 'b0;
ctrl = 'b0;
iValid = 'b0;
end
endtask // init_signals
//----------------------------------------------------------------------------------
// Reset DUT
//----------------------------------------------------------------------------------
task reset_dut();
begin
#15 rstn = 'b0;
#15 rstn = 'b1;
$display("DUT is Reset...");
end
endtask // reset_dut
//----------------------------------------------------------------------------------
endmodule