module and_gate(input a, input b, output y);
assign y = a & b;
endmodule
module and_gate_tb;
  reg a, b;
  wire y;
  and_gate uut(.a(a), .b(b), .y(y));
  initial begin
    $monitor("a=%b b=%b y=%b", a, b, y);
    a=0; b=0; #10;
    a=0; b=1; #10;
    a=1; b=0; #10;
    a=1; b=1; #10;
    $finish;
  end
endmodule
module or_gate(input a, input b, output y);
  assign y = a | b;
endmodule
module or_gate_tb;
  reg a, b;
  wire y;
  or_gate uut(.a(a), .b(b), .y(y));
  initial begin
    $monitor("a=%b b=%b y=%b", a, b, y);
    a=0; b=0; #10;
    a=0; b=1; #10;
    a=1; b=0; #10;
    a=1; b=1; #10;
    $finish;
  end
endmodule
module not_gate(input a, output y);
  assign y = ~a;
endmodule
module not_gate_tb;
  reg a;
  wire y;
  not_gate uut(.a(a), .y(y));
  initial begin
    $monitor("a=%b y=%b", a, y);
    a=0; #10;
    a=1; #10;
    $finish;
  end
endmodule
module xor_gate(input a, input b, output y);
  assign y = a ^ b;
endmodule
module xor_gate_tb;
  reg a, b;
  wire y;
  xor_gate uut(.a(a), .b(b), .y(y));
  initial begin
    $monitor("a=%b b=%b y=%b", a, b, y);
    a=0; b=0; #10;
    a=0; b=1; #10;
    a=1; b=0; #10;
    a=1; b=1; #10;
    $finish;
  end
endmodule
module sr_ff(input S, input R, input clk, output reg Q);
  always @(posedge clk) begin
    if (S & ~R) Q <= 1;
    else if (~S & R) Q <= 0;
    else if (S & R) Q <= 1'bx; // Invalid state
  end
endmodule
module sr_ff_tb;
  reg S, R, clk;
  wire Q;
  sr_ff uut(.S(S), .R(R), .clk(clk), .Q(Q));
  initial begin
    clk=0;
    forever #5 clk = ~clk;
  end
  initial begin
    $monitor("clk=%b S=%b R=%b Q=%b", clk, S, R, Q);
    S=0; R=0; #10;
    S=1; R=0; #10;
    S=0; R=1; #10;
    S=1; R=1; #10;
    $finish;
  end
endmodule
module jk_ff(input J, input K, input clk, output reg Q);
  always @(posedge clk) begin
    case ({J, K})
        2'b00: Q <= Q;
        2'b01: Q <= 0;
        2'b10: Q <= 1;
        2'b11: Q <= ~Q;
    endcase
  end
endmodule
module jk_ff_tb;
  reg J, K, clk;
  wire Q;
  jk_ff uut(.J(J), .K(K), .clk(clk), .Q(Q));
  initial begin
    clk=0;
    forever #5 clk = ~clk;
  end
  initial begin
    $monitor("clk=%b J=%b K=%b Q=%b", clk, J, K, Q);
    J=0; K=0; #10;
    J=1; K=0; #10;
    J=0; K=1; #10;
    J=1; K=1; #10;
    $finish;
  end
endmodule
module t_ff(input T, input clk, output reg Q);
  always @(posedge clk) begin
    if (T)
        Q <= ~Q;
  end
endmodule
module t_ff_tb;
  reg T, clk;
  wire Q;
  t_ff uut(.T(T), .clk(clk), .Q(Q));
  initial begin
    clk=0;
    forever #5 clk = ~clk;
  end
  initial begin
    $monitor("clk=%b T=%b Q=%b", clk, T, Q);
    T=0; #10;
    T=1; #10;
    T=1; #10;
    T=0; #10;
    $finish;
  end
endmodule
module d_ff(input D, input clk, output reg Q);
     always @(posedge clk) begin
       Q <= D;
     end
endmodule
module d_ff_tb;
     reg D, clk;
     wire Q;
     d_ff uut(.D(D), .clk(clk), .Q(Q));
     initial begin
       clk=0;
       forever #5 clk = ~clk;
     end
     initial begin
       $monitor("clk=%b D=%b Q=%b", clk, D, Q);
       D=0; #10;
       D=1; #10;
       D=0; #10;
       D=1; #10;
       $finish;
     end
endmodule
module adder_4bit(
     input [3:0] a, b,
     output [4:0] sum
);
     assign sum = a + b;
endmodule
module tb_adder_4bit;
     reg [3:0] a, b;
     wire [4:0] sum;
     adder_4bit uut (a, b, sum);
     initial begin
       $monitor("a=%d b=%d sum=%d", a, b, sum);
       a=4; b=3;
       #10 a=7; b=5;
       #10 a=15; b=1;
       #10 $finish;
     end
endmodule
module adder_8bit(
     input [7:0] a, b,
     output [8:0] sum
);
     assign sum = a + b;
endmodule
module tb_adder_8bit;
     reg [7:0] a, b;
     wire [8:0] sum;
     adder_8bit uut (a, b, sum);
     initial begin
       $monitor("a=%d b=%d sum=%d", a, b, sum);
       a=25; b=75;
       #10 a=128; b=128;
       #10 a=200; b=55;
       #10 $finish;
     end
endmodule
module multiplier_8bit(
     input [7:0] a, b,
     output [15:0] product
);
     assign product = a * b;
endmodule
module tb_multiplier_8bit;
     reg [7:0] a, b;
     wire [15:0] product;
     multiplier_8bit uut (a, b, product);
     initial begin
       $monitor("a=%d b=%d product=%d", a, b, product);
       a=10; b=20;
       #10 a=15; b=12;
       #10 a=255; b=2;
       #10 $finish;
     end
endmodule
module mux8bit_2to1(
     input [7:0] a, b,
     input sel,
     output [7:0] y
);
     assign y = sel ? b : a;
endmodule
module tb_mux8bit_2to1;
     reg [7:0] a, b;
     reg sel;
     wire [7:0] y;
     mux8bit_2to1 uut (a, b, sel, y);
     initial begin
       $monitor("a=%d b=%d sel=%b y=%d", a, b, sel, y);
       a=20; b=30; sel=0;
       #10 sel=1;
       #10 $finish;
     end
endmodule
module divider_8bit(
     input [7:0] a, b,
     output [7:0] quotient, remainder
);
     assign quotient = a / b;
     assign remainder = a % b;
endmodule
module tb_divider_8bit;
  reg [7:0] a, b;
  wire [7:0] quotient, remainder;
  divider_8bit uut (a, b, quotient, remainder);
  initial begin
    $monitor("a=%d b=%d quotient=%d remainder=%d", a, b, quotient, remainder);
    a=50; b=7;
    #10 a=100; b=10;
    #10 a=200; b=30;
    #10 $finish;
  end
endmodule