/*

                /CHECK FOR BELL
5276 72ED  CLA
5277 1121  TAD BLCNT
5300 7001  IAC
5301 3121  DCA BLCNT
5302 1121  TAD BLCNT
5303 7640  SZA CLA
5304 5147  JMP START+3
5305 1122  TAD BLCON
5306 3121  DCA BLCNT
                /RING BELL
5307 1120  TAD BEL
5310 6046  TLS
5311 6041  TSF
5312 5311  JMP .-1
5313 6042  TCF
5314 5147  JMP START+3
                $
*/

`timescale 1ns / 1ps
`include "defines.v"


module PDP_simulation;

parameter PS_PER_US = 1000000;
parameter PS_PER_MS = 1000000000;
parameter PS_PER_S  = 1000000000000;

parameter SIM_FINISH_DELAY = 3 * PS_PER_S;


    reg clk;
    reg [7:0] sw;
    reg [3:0] btn;

    wire [7:0] Led;
    wire [6:0] seg;
    wire dp;
    wire [3:0] an;
    wire RsTx;
    reg RsRx;

    // Automatic CONT support for MAINDEC diagnostics.
    // Some MAINDEC programs intentionally execute HLT and wait for the
    // operator to press CONT. In simulation we emulate that button press.
    reg auto_cont_enable;
    integer auto_cont_count;
    parameter AUTO_CONT_MAX = 100;
    parameter AUTO_CONT_DELAY = 200;
    parameter AUTO_CONT_WIDTH = 200;

    // Debug / breakpoint counters.
    integer trace_count = 0;
    //integer loop_hits = 0;
    reg [11:0] last_PC = 12'o0000;

    PDP_top uut (
        .clk(clk),
        .sw(sw),
        .Led(Led),
        .btn(btn),
        .seg(seg),
        .dp(dp),
        .an(an),
        .RsTx(RsTx),
        .RsRx(RsRx)
    );

    
    initial begin
        $dumpfile("pdp8.vcd");
        $dumpvars(0, PDP_simulation);
    end
    

    initial begin
        clk = 1'b0;
        forever #10 clk = ~clk;
    end

    initial begin
        $display("Debug trace started");
    end

    task press_cont;
    begin
        #AUTO_CONT_DELAY;
        btn[2] = 1'b1;
        $display("t=%0t  AUTO CONT asserted", $time);

        #AUTO_CONT_WIDTH;
        btn[2] = 1'b0;
        $display("t=%0t  AUTO CONT released", $time);
    end
    endtask

    always @(posedge btn[0])
        $display("t=%0t  RESET button asserted", $time);

    always @(negedge btn[0])
        $display("t=%0t  RESET button released", $time);

    always @(posedge btn[2])
        $display("t=%0t  CONT/RUN button asserted", $time);

    always @(negedge btn[2])
        $display("t=%0t  CONT/RUN button released", $time);

    always @(posedge uut.CU.run)
        $display("t=%0t  RUN became 1", $time);

    always @(negedge uut.CU.run) begin
        $display("t=%0t  RUN became 0", $time);

        if (auto_cont_enable && (auto_cont_count < AUTO_CONT_MAX)) begin
            auto_cont_count = auto_cont_count + 1;
            $display("t=%0t  HLT/operator stop detected, auto CONT count=%0d",
                $time, auto_cont_count);
            press_cont;
        end
        else if (auto_cont_enable && (auto_cont_count >= AUTO_CONT_MAX)) begin
            $display("t=%0t  AUTO CONT limit reached; leaving CPU halted", $time);
        end
    end

   	always @(posedge btn[0]) $display("t=%0t  RESET button asserted", $time);
	always @(negedge btn[0]) $display("t=%0t  RESET button released", $time);
	always @(posedge btn[2]) $display("t=%0t  CONT/RUN button asserted", $time);
	always @(negedge btn[2]) $display("t=%0t  CONT/RUN button released", $time);

	always @(posedge uut.CU.run)  $display("t=%0t  RUN became 1", $time);
	always @(negedge uut.CU.run)  $display("t=%0t  RUN became 0", $time);

/*    always @(posedge uut.clk2) begin
        #1;
        if (!uut.reset) begin
            $display("t=%0t uPC=%03d PC=%04o IR=%04o AC=%04o",
                $time,
                uut.CU.uPCBUS,
                uut.CU.PC,
                uut.CU.IR,
                uut.CU.AC
            );
        end
    end */
 /*   always @(posedge uut.clk2) begin
        #1;
        if (!uut.reset) begin
            $display("t=%0t  btn0=%0d btn2=%0d CONT_key=%0d sw0=%0d sw7=%0d run=%0d halt_req=%0d uPC=%03d PC=%04o IR=%04o AC=%04o",
                $time,
                btn[0],
                btn[2],
                uut.CU.CONT_key,
                sw[0],
                sw[7],
                uut.CU.run,
                uut.CU.halt_req,
                uut.CU.uPCBUS,
                uut.CU.PC,
                uut.CU.IR,
                uut.CU.AC
            );
        end
    end*/
 /*   always @(posedge clk) begin
        if (uut.reset) begin
            trace_count <= 0;
            loop_hits   <= 0;
            last_PC     <= 12'o0000;
        end
        else begin
            trace_count <= trace_count + 1;

            // Breakpoint: detect return to the beginning of the diagnostic loop.
            // The first hit is the first entry at 4200.
            // The second hit means one complete loop has been completed.
            if ((uut.CU.PC == 12'o4200) && (last_PC != 12'o4200)) begin
                loop_hits = loop_hits + 1;

					$display("LOOP HIT %0d: t=%0t PC=%0o IR=%0o AC=%0o uPC=%0d",
						loop_hits,
						$time,
						uut.CU.PC,
						uut.CU.IR,
						uut.CU.AC,
						uut.CU.uPCBUS
					);

                if (loop_hits == 10) begin
                    $display("One complete loop completed.");
                    $finish;
                end
            end

            last_PC <= uut.CU.PC;

           
            //if (trace_count == 10000) begin
            //    trace_count <= 0;

                $display("-t=%0t  btn0=%0d btn2=%0d CONT_key=%0d sw0=%0d sw7=%0d run=%0d halt_req=%0d uPC=%0d PC=%0o IR=%0o AC=%0o",
                    $time,
                    btn[0],
                    btn[2],
                    uut.CU.CONT_key,
                    sw[0],
                    sw[7],
                    uut.CU.run,
                    uut.CU.halt_req,
                    uut.CU.uPCBUS,
                    uut.CU.PC,
                    uut.CU.IR,
                    uut.CU.AC
                );
            //end
            
        end*/
    

    initial begin
        RsRx = 1'b1;
        btn  = 4'b0000;
        sw   = 8'b00000000;
        auto_cont_enable = 1'b0;
        auto_cont_count = 0;

        #10000;
        $display("t=%0t  stimulus start", $time);

        #100;
        sw[0] = 1'b1;    // bootstrap -> 0200
        $display("t=%0t  sw0 set to 1", $time);

        #20;
        btn[0] = 1'b1;
        $display("t=%0t  forcing RESET=1", $time);

        #120;
        btn[0] = 1'b0;
        $display("t=%0t  forcing RESET=0", $time);

        #200;
        btn[2] = 1'b1;
        $display("t=%0t  forcing CONT=1", $time);

        #200;
        btn[2] = 1'b0;
        $display("t=%0t  forcing CONT=0", $time);

        #100;
        auto_cont_enable = 1'b1;
        $display("t=%0t  AUTO CONT enabled", $time);

      //#50000000;
      #5000000;
        $display("t=%0t  simulation finish", $time);
        $finish;
    end

endmodule