// 6.111 Lab 2, Exercise 1

// establish time units for delays used in test module
`timescale 1 ns / 100 ps

// module to emulate 74LS163 synchronous counter
// remember load and clear are active low signals!
module LS163(clk,ent,enp,load,clear,cin[0],cin[1],cin[2],cin[3],
	     cout[0],cout[1],cout[2],cout[3],rco);
   input  clk,ent,enp,load,clear;
   input [3:0] cin;
   output rco;
   output [3:0] cout;
   reg [3:0] cout;

always @ (posedge clk) begin
    cout <= ~clear ? 4'b0 : (~load ? cin : ((ent & enp) ? cout+1 : cout));
end

assign rco = ent ? ((cout === 4'b1111) ? 1'b1 : 1'b0) : 1'b0;

endmodule // LS163

// top level test module
module test();
  integer count;
  reg clk,ent,enp,ld_bar,clr_bar;
  reg [3:0] in,temp;
  wire [3:0] out;
  wire rco;

  // make an instance of LS163
  LS163 test(clk,ent,enp,ld_bar,clr_bar,in[0],in[1],in[2],in[3],
	     out[0],out[1],out[2],out[3],rco);

  // clk has 50% duty cycle, 100ns period
  initial begin
    clk = 0;
    forever #50 clk = ~clk;
  end
  
  initial begin
    $display("Starting test of LS163...");

    // clear the counter
    in = 13;
    ld_bar = 1;
    clr_bar = 0;
    ent = 0;
    enp = 0;
    #100
    if (out !== 0) begin
      $display("clear was asserted low, but counter didn't clear");
      $display("out = %b, expected 0000",out);
      $stop();
    end

    // make it count to 15
    clr_bar = 1;
    ent = 1;
    enp = 1;
    for (count = 1; count <= 15; count = count + 1) begin
      #100
      temp = count;  // so we can print it nicely!
      if (out !== count) begin
        $display("ent and enp are asserted, but counter didn't count");
        $display("out = %b, expected %b",out,temp);
        $stop();
      end
      if (count === 15) begin
        if (rco !== 1) begin
          $display("ent and enp are asserted and out == 15, but rco isn't 1");
          $stop();
        end
      end
      else begin
        if (rco !== 0) begin
          $display("ent and enp are asserted and out == %b, but rco isn't 0",out);
          $stop();
        end
      end
    end
      
    // deassert ENT, check RCO
    ent = 0;
    #10
    if (rco !== 0) begin
      $display("ent is deasserted, but rco isn't 0");
      $stop();
    end
    #90
    if (out !== 15) begin
      $display("ent is deasserted, but counter incremented");
      $display("out = %b, expected 1111",out);
      $stop();
    end

    // deassert ENP
    ent = 1;
    enp = 0;
    #100
    if (out !== 15) begin
      $display("enp is deasserted, but counter incremented");
      $display("out = %b, expected 1111",out);
      $stop();
    end

    // test that clear is synchronous
    ent = 1;
    enp = 1;
    clr_bar = 0;
    #10
    if (out !== 15) begin
      $display("clear is asserted low, but counter cleared before clock edge");
      $display("out = %b, expected 1111",out);
      $stop();
    end
    #90
    if (out !== 0) begin
      $display("clear is asserted low, but counter didn't clear");
      $display("out = %b, expected 1111",out);
      $stop();
    end

    // test that load is synchronous
    ent = 1;
    enp = 1;
    clr_bar = 1;
    ld_bar = 0;
    #10
    if (out !== 0) begin
      $display("load is asserted low, but counter loaded before clock edge");
      $display("out = %b, expected 0000",out);
      $stop();
    end
    #90
    if (out !== in) begin
      $display("load is asserted low, but counter didn't load");
      $display("out = %b, expected %b",out,in);
      $stop();
    end

    $display("Finished test of LS163...");
    $stop();
  end    
  
endmodule // test
