////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 1995-2003 Xilinx, Inc.
// All Right Reserved.
////////////////////////////////////////////////////////////////////////////////
//   ____  ____ 
//  /   /\/   / 
// /___/  \  /    Vendor: Xilinx 
// \   \   \/     Version : 8.1.03i
//  \   \         Application : ISE
//  /   /         Filename : cpu_tb.tfw
// /___/   /\     Timestamp : Mon Nov 12 01:08:47 2007
// \   \  /  \ 
//  \___\/\___\ 
//
//Command: 
//Design Name: cpu_tb
//Device: Xilinx
//
`timescale 1ns/1ps

module cpu_tb;
    wire [31:0] addr;
    reg [31:0] data$inout$reg = 32'b00000000000000000000000000000000;
    // wire [31:0] data = data$inout$reg;
		wire [31:0] data;
    wire readmem;
    wire writemem;
    reg intrq = 1'b0;
    wire [1:0] type;
    reg rst = 1'b1;
    reg clk = 1'b0;

    parameter PERIOD = 20;
    // parameter real DUTY_CYCLE = 0.5;
    parameter OFFSET = 0;

    initial    // Clock process for clk
    begin
        #OFFSET;
        forever
        begin
            clk = 1'b0;
//            #(PERIOD-(PERIOD*DUTY_CYCLE)) clk = 1'b1;
//            #(PERIOD*DUTY_CYCLE);
              #10 clk = 1'b1;
              #10;
       end
    end
		
		wire waitcpu_r;
		wire waitcpu_w;

		wire waitcpu = waitcpu_r | waitcpu_w;

		wire rdack;
		wire wrtack;
	
		wire rdack_A;
		wire rdack_B;
		
		wire wrtack_A;
		wire wrtack_B;
		
		assign rdack = rdack_A | rdack_B;
		assign wrtack = wrtack_A | wrtack_B;
	
		wire sel_A;
		wire sel_B;
	
    cpu UUT (
        .addr(addr),
        .data(data),
        .readmem(readmem),
        .writemem(writemem),
				.waitrq(waitcpu),
        .intrq(intrq),
        .type(type),
        .rst(rst),
        .clk(clk));
				
	
		assign rdack = rdack_A | rdack_B;
		assign wrtack = wrtack_A | wrtack_B;
	
	
		wait_admin w_admin_r (.mem_op (readmem), .dtack(rdack), .waitrq(waitcpu_r), .rst(rst), .clk(clk));
		wait_admin w_admin_w (.mem_op (writemem), .dtack(wrtack), .waitrq(waitcpu_w), .rst(rst), .clk(clk));
		
		wire [3:0] ssrmem;
		wire [3:0] wemem;
		wire [3:0] enmem;
		wire [3:0] enmem1;
		
		wire [31:0] datamem_o;
		wire [31:0] datamem_i;
		
		wire [31:0] data_b_w;
		wire [31:0] data_b_r;
		
		wire [31:0] amem_w;
		wire [31:0] amem_r;

		wire[31:0] addrmem;
		wire[31:0] datamem;
		wire[3:0] wmem;
		
		
		assign sel_B = &(addr[31:28]);
		assign sel_A = ~sel_B;

		
		mem_adaptor_w_xp maw0_A (.dinbus(data_b_w),.abus(addr), .enbus(1'b1), .webus(writemem & sel_A),
														.ssrbus(1'b0), .write_ack(wrtack_A),
												.doutmem(datamem_o), .amem(amem_w), .enmem(enmem1),
													.wemem(wmem), .ssrmem(ssrmem), .type(type), .clk(clk));
		
		mem_adaptor_r_xp mar0_A (.doutbus(data_b_r),.abus(addr), .enbus(readmem & sel_A),
														.ssrbus(1'b0), .read_ack (rdack_A),
												.dinmem(datamem_i), .amem(amem_r), .enmem(enmem),
													.ssrmem(ssrmem), .type(type), .clk(clk));
	
		
		assign addrmem = writemem ? amem_w : amem_r;

		assign datamem = writemem ? datamem_o : 32'bz;
		
		assign datamem_i = ((~writemem)) ? datamem : 32'bz;
		
/*
		assign data = rdack ? data_b_r : 32'bz;
*/
		
		assign data_b_w = writemem ? data : 32'bz;
		
				
		mem_sync main_mem_A (.addr(addrmem), .data(datamem), .en(enmem), .write(wmem), .clk(clk));


		wire [3:0] ssrmem_B;
		wire [3:0] wemem_B;
		wire [3:0] enmem_B;
		wire [3:0] enmem1_B;
		
		wire [31:0] datamem_o_B;
		wire [31:0] datamem_i_B;
		
		wire [31:0] data_b_w_B;
		wire [31:0] data_b_r_B;
		
		wire [31:0] amem_w_B;
		wire [31:0] amem_r_B;

		wire[31:0] addrmem_B;
		wire[31:0] datamem_B;
		wire[3:0] wmem_B;
		
		
		wire[31:0] addr_B = {19'b0,addr[12:0]};
		
		mem_adaptor_w_xp maw0_B (.dinbus(data_b_w_B),.abus(addr_B), .enbus(1'b1), .webus(writemem & sel_B),
														.ssrbus(1'b0), .write_ack(wrtack_B),
												.doutmem(datamem_o_B), .amem(amem_w_B), .enmem(enmem1_B),
													.wemem(wmem_B), .ssrmem(ssrmem_B), .type(type), .clk(clk));
		
		mem_adaptor_r_xp mar0_B (.doutbus(data_b_r_B),.abus(addr_B), .enbus(readmem & sel_B),
														.ssrbus(1'b0), .read_ack (rdack_B),
												.dinmem(datamem_i_B), .amem(amem_r_B), .enmem(enmem_B),
													.ssrmem(ssrmem_B), .type(type), .clk(clk));
	
		
		assign addrmem_B = writemem ? amem_w_B : amem_r_B;

		assign datamem_B = writemem ? datamem_o_B : 32'bz;
		
		assign datamem_i_B = ((~writemem)) ? datamem_B : 32'bz;

/*		
		assign data = rdack_B ? data_b_r_B : 32'bz;
*/

		reg[31:0] data_cpu;

		assign data = data_cpu;

		always @(rdack, rdack_B, data_b_r, data_b_r_B)
			begin
				if (rdack_A)
					begin
						data_cpu <= data_b_r;
					end
				else if (rdack_B)
					begin
						data_cpu <= data_b_r_B;
					end
				else
					begin
						data_cpu <= 32'bz;
					end
			end

		
		assign data_b_w_B = writemem ? data : 32'bz;

		mem_sync_VGA main_mem_B (.addr(addrmem_B), .data(datamem_B), .en(enmem_B), .write(wmem_B), .clk(clk));

		/*
		mem_sync_dual main_mem_B ( .ena(enmem_B & enmem1_B), 
							.dia(datamem_o_B), .doa(datamem_i_B), 
							.addra(addrmem_B[12:0]), .wea(wmem_B),
							.ssra(4'b0), .clka(clk) );
		*/

    integer TX_FILE = 0;
    integer TX_ERROR = 0;

		initial
		begin

/*
			$monitor ( "addr = %h data = %h readmem = %h writemem = %h regA = %h regB = %h aluOP_h = %h tos = %h dsp = %h micr_pc = %h pc = %h ir = %h clk= %h",
								addr, data, readmem, writemem, UUT.regA, UUT.regB, UUT.aluOp_h, UUT.tos, UUT.dsp, UUT.micr_pc, UUT.pc, UUT.ir, clk ); 

*/

/*

	 		$monitor ("addr = %h writemem = %h ir = %h pc = %h to_page_zero = %h pcb_source = %h template = %h regA = %h regB = %h dsp = %h tos = %h", 
					addr, writemem, UUT.ir, UUT.pc, UUT.to_page_zero, UUT.pcb_source, UUT.template, UUT.regA, UUT.regB, 
					UUT.dsp, UUT.tos );

*/

/*
			$monitor ("ir = %h tos = %h micr_pc = %h dsp = %h", 
				UUT.ir, UUT.tos, UUT.micr_pc, UUT.dsp);
*/

/*
			$monitor ("mcs_data = %h , ir = %h data = %h enbus = %h enbus_1 = %h rack = %h readmem = %h writemem = %h waitcpu_w = %h micr_pc = %h clk = %h", 
				UUT.mic_inst_raw, UUT.ir, data, mar0.enbus, mar0.enbus_1, rdack, readmem, writemem, waitcpu_w, UUT.micr_pc, clk);

*/

/*
			$monitor ("rst = %h, mcs_data = %h , micr_pc_new = %h, waitrq = %h mic_inst = %h to_page_zero = %h dispatch = %h mic_next = %h readmem = %h writemem = %h waitcpu_w = %h micr_pc = %h clk = %h", 
				rst, UUT.mic_inst_raw, UUT.micr_pc_new, UUT.waitrq, UUT.mic_inst, UUT.to_page_zero, UUT.dispatch, UUT.mic_next, readmem, writemem, waitcpu_w, UUT.micr_pc, clk);

*/

 
		end


    
    initial begin  // Open the results file...
        TX_FILE = $fopen("results.txt");
        #1000000000000 // old pFinal time:  1020 ns
				
				// $put_char_out(100,100,3);				
				
				$displayh ( UUT.ir );
				// $close_window ();
        if (TX_ERROR == 0) begin
            $display("No errors or warnings.");
            $fdisplay(TX_FILE, "No errors or warnings.");
        end else begin
            $display("%d errors found in simulation.", TX_ERROR);
            $fdisplay(TX_FILE, "%d errors found in simulation.", TX_ERROR);
        end
        $fclose(TX_FILE);
        $stop;
    end

    initial begin
        // -------------  Current Time:  29ns
        #25;
        rst = 1'b0;
        data$inout$reg = 32'bZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ;
        // -------------------------------------
    end

		wire[31:0] stopSimu, kp, kr;
		reg[31:0] kp_o, kr_o;


		initial begin		
				#0;
				forever
					begin
						@(posedge clk);
						
						kp_o = kp;
						kr_o = kr;
						
						#1;

						$get_c_data (stopSimu, kp, kr);

						if (stopSimu[0])
							begin
								$displayh ( UUT.ir );
								// $close_window ();
        				if (TX_ERROR == 0) begin
            				$display("No errors or warnings.");
            				$fdisplay(TX_FILE, "No errors or warnings.");
        				end else begin
            				$display("%d errors found in simulation.", TX_ERROR);
            				$fdisplay(TX_FILE, "%d errors found in simulation.", TX_ERROR);
        				end
        				$fclose(TX_FILE);
        				$stop;
							end
						#1;
						if (!(kp == kp_o))
							begin
								$display ( "key pressed = %h", kp );
							end
							
						if (!(kr == kr_o))
							begin
								$display ( "key released = %h", kr );
							end
						

/*
						if (rdack_B)
							begin
								$display ( "data = %h data_cpu = %h data_b_r_B = %h", data, data_cpu, data_b_r_B );
							end
*/
/*

						if (addr[31])
							begin
								$display ( "addr = %h ", addr[31:0]);
							end
*/

/*
						if (sel_B == 1'b1)
							begin
								$get_c_data ( aa, bb, cc );
								$display ( "selB = %h aa = %h bb = %h cc = %h", sel_B, aa, bb, cc );
							end
*/

						if (UUT.ir == 32'hff3c0000)
							begin
								$display ("**** print %h ", UUT.tos );
							end

					end
		end


    task CHECK_addr;
        input [31:0] NEXT_addr;

        #0 begin
            if (NEXT_addr !== addr) begin
                $display("Error at time=%dns addr=%b, expected=%b", $time, addr, NEXT_addr);
                $fdisplay(TX_FILE, "Error at time=%dns addr=%b, expected=%b", $time, addr, NEXT_addr);
                $fflush(TX_FILE);
                TX_ERROR = TX_ERROR + 1;
            end
        end
    endtask
    task CHECK_readmem;
        input NEXT_readmem;

        #0 begin
            if (NEXT_readmem !== readmem) begin
                $display("Error at time=%dns readmem=%b, expected=%b", $time, readmem, NEXT_readmem);
                $fdisplay(TX_FILE, "Error at time=%dns readmem=%b, expected=%b", $time, readmem, NEXT_readmem);
                $fflush(TX_FILE);
                TX_ERROR = TX_ERROR + 1;
            end
        end
    endtask
    task CHECK_writemem;
        input NEXT_writemem;

        #0 begin
            if (NEXT_writemem !== writemem) begin
                $display("Error at time=%dns writemem=%b, expected=%b", $time, writemem, NEXT_writemem);
                $fdisplay(TX_FILE, "Error at time=%dns writemem=%b, expected=%b", $time, writemem, NEXT_writemem);
                $fflush(TX_FILE);
                TX_ERROR = TX_ERROR + 1;
            end
        end
    endtask
    task CHECK_type;
        input [1:0] NEXT_type;

        #0 begin
            if (NEXT_type !== type) begin
                $display("Error at time=%dns type=%b, expected=%b", $time, type, NEXT_type);
                $fdisplay(TX_FILE, "Error at time=%dns type=%b, expected=%b", $time, type, NEXT_type);
                $fflush(TX_FILE);
                TX_ERROR = TX_ERROR + 1;
            end
        end
    endtask

endmodule

