```///  LSU EE 4755 -- Fall 2020 -- Digital Design / HDL
//
/// Verilog Notes -- Synthesis of Sequential Logic Examples
//
/// This file is a supplement to the lecture slides
/// Visit https://www.ece.lsu.edu/v/2020/lsli-syn-seq.pdf

/// Under Construction

/// Contents
//

/// References

// :SV12: IEEE 1800-2012 -- The SystemVerilog Standard
// :SV17: IEEE 1800-2017 -- The SystemVerilog Standard
//        https://ieeexplore.ieee.org/document/8299595/
//        This is for those already familiar with Verilog.
//
// :BV3:  Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
//        The text used in LSU EE 2740.

/// Preview of Blocking and Non-Block Assignments
///
//
// :SV12: Section 9.4.5

module verilog_stuff(input uwire a);

logic [7:0] b, c, d, e;

initial begin

b = 0;
c1 = b;

#1;

// Nonblocking assignment.
lhs <= some_expression + some_other_expression;

b <= 1;
c2 = b;

#2;

c3 = b;

end

initial b = 0;
always @( posedge a ) begin

c <= b;
b <= 1;

end

always @( posedge a ) begin

e <= b;
b <= 2;

end

endmodule

/// First Examples of Inferred Registers
///

module testc;

logic clk;

counter myc(count, r, clk);

initial clk = 0;
always #10 clk = !clk;

always @( count ) \$write("The counter is now %0d\n", count);

endmodule

module counter
#( int w = 16 )
( output logic [w-1:0] count,
input uwire reset, clk );

always_ff @( posedge clk )
begin
count = count + 1;
end

endmodule

module counter
#( int w = 16 )
(output logic [w-1:0] count, input uwire reset, clk );

always @( posedge clk ) begin

if ( reset )
count = 0;
else
count++;

end

endmodule

module counter
#( int w = 16 )
(output logic [w-1:0] c, input uwire reset, clk );

always_ff @( posedge clk ) begin

c = c + 1;

if ( reset ) c = 0;

end

endmodule

/// Examples of Describing Common Register Types
///

// Behavioral description of d flip-flop.
//
module d_ff(output logic q, input uwire d, clk);

always_ff @( posedge clk ) q <= d;

endmodule // d_ff

module register #( int width = 16 )
( output logic [width-1:0] val,
input uwire [width-1:0] data,
input uwire clk );

always_ff @( posedge clk ) val <= data;

endmodule

module register_en
#( int width = 16 )
( output logic [width-1:0] val,
input uwire enable,
input uwire [width-1:0] data,
input uwire clk );

always_ff @( posedge clk iff enable ) val <= data;

endmodule

module register_en
#( int width = 16 )
( output logic [width-1:0] val,
input uwire enable,
input uwire [width-1:0] data,
input uwire clk );

always_ff @( posedge clk ) begin
if ( a ) begin
if ( enable ) val = data;
val = val + 3;
if ( e2 ) val = val * 5;
end

x = val + val2;
end

always_ff @( posedge clk ) begin

x = val + val2;
end

endmodule

module register_sync_reset
#( int width = 16 )
( output logic [width-1:0] val,
input uwire reset,
input uwire [width-1:0] data,
input uwire clk );

always_ff @( posedge clk ) if ( reset ) val <= 0; else val <= data;

endmodule

module register_async_reset
#( int width = 16 )
( output logic [width-1:0] val,
input uwire reset,
input uwire [width-1:0] data,
input uwire clk );

always_ff @( posedge clk or posedge reset )
if ( reset ) val <= 0; else val <= data;

endmodule

/// Examples of Counters
///

module count
#( int bits = 16 )
( output logic [bits-1:0] c,
input uwire clk );

initial c = 0;

always @( posedge clk ) c++;

endmodule

module count_reset
#( int bits = 16 )
( output logic [bits-1:0] c,
input uwire reset,
input uwire clk );

always_ff @( posedge clk ) if ( reset ) c <= 0; else c <= c + 1;

endmodule

module count_thd
#( int bits = 16 )
( output logic [bits-1:0] c,
output logic over_th,
input uwire [bits-1:0] threshold,
input uwire clk );

always_ff @( posedge clk )
begin
c++;
over_th = c > threshold;
end

endmodule

module count_thd_alt2
#( int bits = 16 )
( output logic [bits-1:0] c,
output logic over_th,
input uwire [bits-1:0] threshold,
input uwire clk );

always_ff @( posedge clk )
begin
over_th = c > threshold;
c++;
end

// No delay constraints.
// over_th_reg/CLK   setup                    0  +277    4272 R
//   count_thd_alt2     92      15928         0       15928    <none> (D)
// 100 ps delay target
//   c_reg[12]/CLK   setup                    0  +276    1355 R
//   count_thd_alt2    191      24492         0       24492    <none> (D)

endmodule

module count_thd_alt
#( int bits = 16 )
( output logic [bits-1:0] c,
output logic over_th,
input uwire [bits-1:0] threshold,
input uwire clk );

always_ff @( posedge clk ) c++;

always_comb over_th = c > threshold;

// No delay constraints.
//   over_th        out port                      +0    3973 F
//   count_thd_alt     91      15544         0       15544    <none> (D)
// 100 ps delay target
//   c_reg[15]/CLK   setup                    0  +276    1340 R
//   count_thd_alt    189      23160         0       23160    <none> (D)

endmodule

module count_limit
#( int max_val = 9,
int bits = \$clog2(max_val) )
( output logic [bits-1:0] c,
input uwire reset,
input uwire clk );

always_ff @( posedge clk ) begin

if ( reset || c == max_val ) c = 0; else c++;

end

endmodule

`ifdef classroom_live
module bcd_count
#( int num_digits = 4 )
( output uwire [num_digits-1:0][3:0] count,
input uwire clk );

count_limit_en #(9) cl0( count[0], 1'b1, clk );
assign  en1 = count[0] == 9;
count_limit_en #(9) cl1( count[1], en1,  clk );
assign  en2 = count[1] == 9 && en1;
count_limit_en #(9) cl2( count[2], en2,  clk );

endmodule
`endif

module count_limit_en
#( int max_val = 9,
int bits = \$clog2(max_val) )
( output logic [bits-1:0] c,
input uwire reset,
input uwire enable,
input uwire clk );

always_ff @( posedge clk )
if ( reset ) c = 0;
else if ( enable ) begin
if ( c == max_val ) c = 0; else c++;
end

endmodule

module bcd_count
#( int num_digits = 4 )
( output uwire [num_digits-1:0][3:0] count,
input uwire reset,
input uwire clk );

uwire    nines[num_digits:-1];

assign  nines[-1] = 1;

for ( genvar d=0; d<num_digits; d++ )
begin
count_limit_en #(9) cl0( count[d], reset, nines[d-1], clk );
assign nines[d] = nines[d-1] && count[d] == 9;
end
endmodule

module testbench;

localparam int width = 4;
localparam int num_cyc = 115;

logic      clk;
logic      reset;
bit        done;
int cycle;

localparam int max_muts = 4;

uwire [width-1:0] cnt[max_muts];
localparam       int num_digits = 3;
uwire [num_digits-1:0] [3:0] bcd;

count #(width) cm1(cnt[0], clk);
count_reset #(width) cm2(cnt[1], reset, clk);
count_limit #(9) cm3(cnt[2], reset, clk);
bcd_count #(num_digits) cm4(bcd,reset,clk);

initial begin
clk = 0;
cycle = 0;
done = 0;
repeat ( 2 * num_cyc ) #10 cycle += clk++;
done = 1;
end

initial begin

reset = 1;
@( posedge clk ); @( negedge clk );
reset = 0;

do @ ( negedge clk ) begin

\$write("Cyc %4d  cnt %2d  %2d  %2d  %3x\n",
cycle, cnt[0], cnt[1], cnt[2], bcd);

end while ( !done );

end

endmodule