Problem: Prob150_review2015_fsmonehot

Specification:

I would like you to implement a module named TopModule with the following
interface. All input and output ports are one bit unless otherwise
specified.

 - input  d
 - input  done_counting
 - input  ack
 - input  state (10 bits)
 - output B3_next
 - output S_next
 - output S1_next
 - output Count_next
 - output Wait_next
 - output done
 - output counting
 - output shift_ena

The module should implement the following Moore state machine with 3
input (d, done_counting, ack) and 3 outputs (shift_ena, counting, done).
Unless otherwise stated in the diagram below, assume outputs are 0 and
inputs are don't cares.

  S     ()            --d=0--> S
  S     ()            --d=1--> S1
  S1    ()            --d=0--> S
  S1    ()            --d=1--> S11
  S11   ()            --d=0--> S110
  S11   ()            --d=1--> S11
  S110  ()            --d=0--> S
  S110  ()            --d=1--> B0
  B0    (shift_ena=1) --(always go to next cycle)--> B1
  B1    (shift_ena=1) --(always go to next cycle)--> B2
  B2    (shift_ena=1) --(always go to next cycle)--> B3
  B3    (shift_ena=1) --(always go to next cycle)--> Count
  Count (counting=1)  --!(done_counting)--> Count
  Count (counting=1)  ---(done_counting)--> Wait
  Wait  (done=1)      --ack=0--> Wait
  Wait  (done=1)      --ack=1--> S

At reset, the state machine starts in state "S". Derive next-state logic
equations and output logic equations by inspection assuming the following
one-hot encoding is used: (S, S1, S11, S110, B0, B1, B2, B3, Count, Wait)
= (10'b0000000001, 10'b0000000010, 10'b0000000100, ... , 10'b1000000000)

Derive state transition and output logic equations by inspection assuming
a one-hot encoding. Implement only the state transition logic and output
logic (the combinational logic portion) for this state machine.

Write code that generates the following equations:

 - B3_next (next-state logic for state B3)
 - S_next
 - S1_next
 - Count_next
 - Wait_next
 - done -- output logic
 - counting
 - shift_ena



Reference implementation:

module RefModule (
  input d,
  input done_counting,
  input ack,
  input [9:0] state, // 10-bit one-hot current state
  output B3_next,
  output S_next,
  output S1_next,
  output Count_next,
  output Wait_next,
  output done,
  output counting,
  output shift_ena
);

  parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;

  assign B3_next = state[B2];
  assign S_next = state[S]&~d | state[S1]&~d | state[S110]&~d | state[Wait]&ack;
  assign S1_next = state[S]&d;
  assign Count_next = state[B3] | state[Count]&~done_counting;
  assign Wait_next = state[Count]&done_counting | state[Wait]&~ack;

  assign done = state[Wait];
  assign counting = state[Count];
  assign shift_ena = |state[B3:B0];

endmodule



Testbench:
`timescale 1 ps/1 ps
`define OK 12
`define INCORRECT 13


module stimulus_gen (
	input clk,
	output reg d, done_counting, ack,
	output reg [9:0] state,
	input tb_match
);
	bit failed = 0;
	bit fail_onehot = 0;
	
	always @(posedge clk, negedge clk)
		if (!tb_match) 
			failed <= 1;
	
	initial begin
		{d, done_counting, ack} <= 3'h0;
		state <= 10'h0;
		
		repeat(300) @(posedge clk, negedge clk) begin
			{d, done_counting, ack} = $random;
			state <= 1<< ($unsigned($random) % 10);
		end

		@(posedge clk) fail_onehot <= failed;

		repeat(3000) @(posedge clk, negedge clk) begin
			{d, done_counting, ack} = $random;
			state <= $random;
		end

		
		@(posedge clk);
		if (!fail_onehot && failed) begin
			$display ("Hint: Your circuit passed when given only one-hot inputs, but not with random inputs.");
			$display ("Hint: Are you doing something more complicated than deriving state transition equations by inspection?\n");
		end

		#1 $finish;
	end
	
endmodule

module tb();

	typedef struct packed {
		int errors;
		int errortime;
		int errors_B3_next;
		int errortime_B3_next;
		int errors_S_next;
		int errortime_S_next;
		int errors_S1_next;
		int errortime_S1_next;
		int errors_Count_next;
		int errortime_Count_next;
		int errors_Wait_next;
		int errortime_Wait_next;
		int errors_done;
		int errortime_done;
		int errors_counting;
		int errortime_counting;
		int errors_shift_ena;
		int errortime_shift_ena;

		int clocks;
	} stats;
	
	stats stats1;
	
	
	wire[511:0] wavedrom_title;
	wire wavedrom_enable;
	int wavedrom_hide_after_time;
	
	reg clk=0;
	initial forever
		#5 clk = ~clk;

	logic d;
	logic done_counting;
	logic ack;
	logic [9:0] state;
	logic B3_next_ref;
	logic B3_next_dut;
	logic S_next_ref;
	logic S_next_dut;
	logic S1_next_ref;
	logic S1_next_dut;
	logic Count_next_ref;
	logic Count_next_dut;
	logic Wait_next_ref;
	logic Wait_next_dut;
	logic done_ref;
	logic done_dut;
	logic counting_ref;
	logic counting_dut;
	logic shift_ena_ref;
	logic shift_ena_dut;

	initial begin 
		$dumpfile("wave.vcd");
		$dumpvars(1, stim1.clk, tb_mismatch ,d,done_counting,ack,state,B3_next_ref,B3_next_dut,S_next_ref,S_next_dut,S1_next_ref,S1_next_dut,Count_next_ref,Count_next_dut,Wait_next_ref,Wait_next_dut,done_ref,done_dut,counting_ref,counting_dut,shift_ena_ref,shift_ena_dut );
	end


	wire tb_match;		// Verification
	wire tb_mismatch = ~tb_match;
	
	stimulus_gen stim1 (
		.clk,
		.* ,
		.d,
		.done_counting,
		.ack,
		.state );
	RefModule good1 (
		.d,
		.done_counting,
		.ack,
		.state,
		.B3_next(B3_next_ref),
		.S_next(S_next_ref),
		.S1_next(S1_next_ref),
		.Count_next(Count_next_ref),
		.Wait_next(Wait_next_ref),
		.done(done_ref),
		.counting(counting_ref),
		.shift_ena(shift_ena_ref) );
		
	TopModule top_module1 (
		.d,
		.done_counting,
		.ack,
		.state,
		.B3_next(B3_next_dut),
		.S_next(S_next_dut),
		.S1_next(S1_next_dut),
		.Count_next(Count_next_dut),
		.Wait_next(Wait_next_dut),
		.done(done_dut),
		.counting(counting_dut),
		.shift_ena(shift_ena_dut) );

	
	bit strobe = 0;
	task wait_for_end_of_timestep;
		repeat(5) begin
			strobe <= !strobe;  // Try to delay until the very end of the time step.
			@(strobe);
		end
	endtask	

	
	final begin
		if (stats1.errors_B3_next) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "B3_next", stats1.errors_B3_next, stats1.errortime_B3_next);
		else $display("Hint: Output '%s' has no mismatches.", "B3_next");
		if (stats1.errors_S_next) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "S_next", stats1.errors_S_next, stats1.errortime_S_next);
		else $display("Hint: Output '%s' has no mismatches.", "S_next");
		if (stats1.errors_S1_next) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "S1_next", stats1.errors_S1_next, stats1.errortime_S1_next);
		else $display("Hint: Output '%s' has no mismatches.", "S1_next");
		if (stats1.errors_Count_next) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "Count_next", stats1.errors_Count_next, stats1.errortime_Count_next);
		else $display("Hint: Output '%s' has no mismatches.", "Count_next");
		if (stats1.errors_Wait_next) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "Wait_next", stats1.errors_Wait_next, stats1.errortime_Wait_next);
		else $display("Hint: Output '%s' has no mismatches.", "Wait_next");
		if (stats1.errors_done) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "done", stats1.errors_done, stats1.errortime_done);
		else $display("Hint: Output '%s' has no mismatches.", "done");
		if (stats1.errors_counting) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "counting", stats1.errors_counting, stats1.errortime_counting);
		else $display("Hint: Output '%s' has no mismatches.", "counting");
		if (stats1.errors_shift_ena) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "shift_ena", stats1.errors_shift_ena, stats1.errortime_shift_ena);
		else $display("Hint: Output '%s' has no mismatches.", "shift_ena");

		$display("Hint: Total mismatched samples is %1d out of %1d samples\n", stats1.errors, stats1.clocks);
		$display("Simulation finished at %0d ps", $time);
		$display("Mismatches: %1d in %1d samples", stats1.errors, stats1.clocks);
	end
	
	// Verification: XORs on the right makes any X in good_vector match anything, but X in dut_vector will only match X.
	assign tb_match = ( { B3_next_ref, S_next_ref, S1_next_ref, Count_next_ref, Wait_next_ref, done_ref, counting_ref, shift_ena_ref } === ( { B3_next_ref, S_next_ref, S1_next_ref, Count_next_ref, Wait_next_ref, done_ref, counting_ref, shift_ena_ref } ^ { B3_next_dut, S_next_dut, S1_next_dut, Count_next_dut, Wait_next_dut, done_dut, counting_dut, shift_ena_dut } ^ { B3_next_ref, S_next_ref, S1_next_ref, Count_next_ref, Wait_next_ref, done_ref, counting_ref, shift_ena_ref } ) );
	// Use explicit sensitivity list here. @(*) causes NetProc::nex_input() to be called when trying to compute
	// the sensitivity list of the @(strobe) process, which isn't implemented.
	always @(posedge clk, negedge clk) begin

		stats1.clocks++;
		if (!tb_match) begin
			if (stats1.errors == 0) stats1.errortime = $time;
			stats1.errors++;
		end
		if (B3_next_ref !== ( B3_next_ref ^ B3_next_dut ^ B3_next_ref ))
		begin if (stats1.errors_B3_next == 0) stats1.errortime_B3_next = $time;
			stats1.errors_B3_next = stats1.errors_B3_next+1'b1; end
		if (S_next_ref !== ( S_next_ref ^ S_next_dut ^ S_next_ref ))
		begin if (stats1.errors_S_next == 0) stats1.errortime_S_next = $time;
			stats1.errors_S_next = stats1.errors_S_next+1'b1; end
		if (S1_next_ref !== ( S1_next_ref ^ S1_next_dut ^ S1_next_ref ))
		begin if (stats1.errors_S1_next == 0) stats1.errortime_S1_next = $time;
			stats1.errors_S1_next = stats1.errors_S1_next+1'b1; end
		if (Count_next_ref !== ( Count_next_ref ^ Count_next_dut ^ Count_next_ref ))
		begin if (stats1.errors_Count_next == 0) stats1.errortime_Count_next = $time;
			stats1.errors_Count_next = stats1.errors_Count_next+1'b1; end
		if (Wait_next_ref !== ( Wait_next_ref ^ Wait_next_dut ^ Wait_next_ref ))
		begin if (stats1.errors_Wait_next == 0) stats1.errortime_Wait_next = $time;
			stats1.errors_Wait_next = stats1.errors_Wait_next+1'b1; end
		if (done_ref !== ( done_ref ^ done_dut ^ done_ref ))
		begin if (stats1.errors_done == 0) stats1.errortime_done = $time;
			stats1.errors_done = stats1.errors_done+1'b1; end
		if (counting_ref !== ( counting_ref ^ counting_dut ^ counting_ref ))
		begin if (stats1.errors_counting == 0) stats1.errortime_counting = $time;
			stats1.errors_counting = stats1.errors_counting+1'b1; end
		if (shift_ena_ref !== ( shift_ena_ref ^ shift_ena_dut ^ shift_ena_ref ))
		begin if (stats1.errors_shift_ena == 0) stats1.errortime_shift_ena = $time;
			stats1.errors_shift_ena = stats1.errors_shift_ena+1'b1; end

	end

   // add timeout after 100K cycles
   initial begin
     #1000000
     $display("TIMEOUT");
     $finish();
   end

endmodule