/* testbench.v - Testbench for the 9086 CPU

   This file is part of the 9086 project.

   Copyright (c) 2024 Efthymios Kritikos

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/*In hz */
`define CPU_SPEED 1000

module tb;
wire clock;
reg reset;
reg  clk_enable;
wire [19:0]address_bus;
wire [15:0]data_bus_write;
wire rd,wr,HALT;
wire [2:0] ERROR;
wire IOMEM;

system system( .clock(clock),
	.reset(reset),
	.address_bus(address_bus),
	.data_bus_write(data_bus_write),
	.rd(rd),
	.wr(wr),
	.HALT(HALT),
	.ERROR(ERROR),
	.IOMEM(IOMEM)
);

clock_gen #(.FREQ(1000)) u1(clk_enable, clock);

string memdump_name;
initial begin
	clk_enable = 1;
	do_reset = 0;
end

reg [2:0]do_reset;

always @(posedge clock) begin
	case(do_reset)
		3'd0:begin
			do_reset<=1;
			end
		3'd1:begin
			do_reset<=2;
			reset <= 0;
			end
		3'd2:begin
			do_reset<=3;
			reset <= 0;
			end
		3'd3:begin
			do_reset<=4;
			reset <= 1;
			end
		3'd4:begin
			end
	endcase
end

endmodule


/*Clock generator*/
module clock_gen (input enable, output reg clk);

parameter FREQ = 1000;  // in HZ
parameter PHASE = 0;    // in degrees
parameter DUTY = 50;    // in percentage

real clk_pd	= 1.0/FREQ * 1000000000; 	// convert to ms
real clk_on	= DUTY/100.0 * clk_pd;
real clk_off	= (100.0 - DUTY)/100.0 * clk_pd;
real quarter	= clk_pd/4;
real start_dly	= quarter * PHASE/90;

reg start_clk;

initial begin
end

// Initialise variables to zero
initial begin
	clk = 0;
	start_clk = 0;
end

// When clock is enabled, delay driving the clock to one in order
// to achieve the phase effect. start_dly is configured to the
// correct delay for the configured phase. When enable is 0,
// allow enough time to complete the current clock period
always @ (posedge enable or negedge enable) begin
	if (enable) begin
		#(start_dly) start_clk = 1;
	end else begin
		#(start_dly) start_clk = 0;
	end
end

// Achieve duty cycle by a skewed clock on/off time and let this
// run as long as the clocks are turned on.
always @(posedge start_clk) begin
	if (start_clk) begin
		clk = 1;

		while (start_clk) begin
			#(clk_on)  clk = 0;
			#(clk_off) clk = 1;
		end

		clk = 0;
	end
end
endmodule
