module cart
(
	input         clk,
	input         clk7_en,
	input         clk7n_en,
	input         cpu_rst,
	input  [23:1] cpu_address_in,
	input         _cpu_as,
	input         cpu_rd,
	input         cpu_hwr,
	input         cpu_lwr,
	input  [31:0] nmi_addr,
	input   [8:1] reg_address_in,
	input  [15:0] reg_data_in,
	input         dbr,
	input         ovl,
	input         freeze, 
	input         cpuhlt,
	output [15:0] cart_data_out,
	output reg    int7 = 1'b0,
	output        sel_cart,
	output        ovr
);


//  cart selected, is in stealth mode until first freeze, has to be available during halt to allow userio 
assign sel_cart = ~dbr && (cpu_address_in[23:19]==5'b1010_0) && (stealth | cpuhlt); // $A00000
   

// latch VBR + NMI vector offset
reg [31:0] nmi_vec_adr=0;
always @ (posedge clk) if (clk7_en) nmi_vec_adr <= nmi_addr; // $7C = NMI vector offset

// override decoding of NMI
assign ovr = active && ~dbr && ~ovl && cpu_rd && (cpu_address_in[23:2] == nmi_vec_adr[23:2]);

// custom NMI vector address output $a1000c
wire [15:0] nmi_adr_out = ovr ? (!cpu_address_in[1] ? 16'h00a1 : 16'h000c) : 16'h0000; 

// freeze button
reg freeze_d=0;
always @ (posedge clk) if (clk7_en) freeze_d <= freeze;

wire freeze_req = freeze && ~freeze_d;

// int7 request
wire int7_req = freeze_req;

// level7 interrupt ack cycle, on Amiga interrupt vector number is read from kickstart rom
wire int7_ack = &cpu_address_in && ~_cpu_as;

// level 7 interrupt request logic
// interrupt request lines are sampled during S4->S5 transition (falling cpu clock edge)
always @ (posedge clk) begin
	if (clk7_en) begin
		     if (cpu_rst)  int7 <= 0;
		else if (int7_req) int7 <= 1;
		else if (int7_ack) int7 <= 0;
	end
end

// latches
reg l_int7_req=0;
reg l_int7_ack=0;
always @ (posedge clk) begin
	if (clk7_en) begin
		l_int7_req <= int7_req;
		l_int7_ack <= int7_ack;
	end
end

reg l_int7=0;
always @ (posedge clk) begin
	if (clk7_en) begin
		     if (cpu_rst)              l_int7 <= 0;
		else if (l_int7_req)           l_int7 <= 1;
		else if (l_int7_ack && cpu_rd) l_int7 <= 0;
	end
end

// overlay active
reg active=0;
reg stealth; //hide till first freeze request   
always @ (posedge clk) begin
	if (clk7_en) begin
		if (cpu_rst) begin
			active <= 0;
			stealth <= 0;
		end
		else if (l_int7 && l_int7_ack && cpu_rd) begin
			active <= 1;
			stealth <= 1;
		end
		else if (sel_cart && cpu_rd) begin
			active <= 0;
		end
	end
end

// custom registers mirror memory
wire sel_custom_mirror = ~dbr && cpu_rd && (cpu_address_in[23:12]==12'b1010_1001_1111) && stealth; // $A9F000

reg [15:0] custom_mirror_q;
reg [15:0] custom_mirror[255:0];
always @ (posedge clk) begin
	if (clk7_en) begin
		custom_mirror[reg_address_in] <= reg_data_in;
	end
	custom_mirror_q <= custom_mirror[cpu_address_in[8:1]];
end

wire [15:0] custom_mirror_out = sel_custom_mirror ? custom_mirror_q : 16'h0000;

// cart data output
assign cart_data_out = custom_mirror_out | nmi_adr_out;


endmodule