module MAPN163(     //signal descriptions in powerpak.v
	input m2,
	input m2_n,
	input clk20,

	input reset,
	input nesprg_we,
	output nesprg_oe,
	input neschr_rd,
	input neschr_wr,
	input [15:0] prgain,
	input [13:0] chrain,
	input [7:0] nesprgdin,
	input [7:0] ramprgdin,
	output reg [7:0] nesprgdout,

	output [7:0] neschrdout,
	output neschr_oe,

	output reg chrram_we,
	output reg chrram_oe,
	output wram_oe,
	output wram_we,
	output prgram_we,
	output prgram_oe,
	output reg [18:10] ramchraout,
	output [18:13] ramprgaout,
	output irq,
	output reg ciram_ce,
	output exp6,

	input cfg_boot,
	input [18:12] cfg_chrmask,
	input [18:13] cfg_prgmask,
	input cfg_vertical,
	input cfg_fourscreen,
	input cfg_chrram,

	input ce,// add
	input mapper210,
	input [3:0] submapper,
	//output [15:0] snd_level,
	input [7:0] audio_dout,
	// savestates              
	input       [63:0]  SaveStateBus_Din,
	input       [ 9:0]  SaveStateBus_Adr,
	input               SaveStateBus_wren,
	input               SaveStateBus_rst,
	input               SaveStateBus_load,
	output      [63:0]  SaveStateBus_Dout
);

assign exp6 = 0;

reg [1:0] chr_en;
reg [5:0] prg89,prgAB,prgCD;
reg [7:0] chr0,chr1,chr2,chr3,chr4,chr5,chr6,chr7,chr10,chr11,chr12,chr13;
reg [1:0] mirror;
wire submapper1 = (submapper == 1);

always@(posedge clk20) begin
	if (reset) begin
		mirror <= cfg_vertical ? 2'b01 : 2'b10;
	end else if (SaveStateBus_load) begin
		chr0   <= SS_MAP1[ 7: 0];
		chr1   <= SS_MAP1[15: 8];
		chr2   <= SS_MAP1[23:16];
		chr3   <= SS_MAP1[31:24];
		chr4   <= SS_MAP1[39:32];
		chr5   <= SS_MAP1[47:40];
		chr6   <= SS_MAP1[55:48];
		chr7   <= SS_MAP1[63:56];
		chr10  <= SS_MAP2[23:16];
		chr11  <= SS_MAP2[31:24];
		chr12  <= SS_MAP2[39:32];
		chr13  <= SS_MAP2[47:40];
		chr_en <= SS_MAP2[49:48];
		prg89  <= SS_MAP2[55:50];
		prgAB  <= SS_MAP2[61:56];
		prgCD  <= SS_MAP3[ 5: 0];
		mirror <= SS_MAP3[ 7: 6];
	end else if(ce && nesprg_we)
		case(prgain[15:11])
			5'b10000: chr0<=nesprgdin;              //8000
			5'b10001: chr1<=nesprgdin;
			5'b10010: chr2<=nesprgdin;              //9000
			5'b10011: chr3<=nesprgdin;
			5'b10100: chr4<=nesprgdin;              //A000
			5'b10101: chr5<=nesprgdin;
			5'b10110: chr6<=nesprgdin;              //B000
			5'b10111: chr7<=nesprgdin;
			5'b11000: chr10<=nesprgdin;             //C000
			5'b11001: chr11<=nesprgdin;
			5'b11010: chr12<=nesprgdin;             //D000
			5'b11011: chr13<=nesprgdin;
			5'b11100: {mirror,prg89}<=nesprgdin;    //E000
			5'b11101: {chr_en,prgAB}<=nesprgdin;    //E800
			5'b11110: prgCD<=nesprgdin[5:0];        //F000
			//5'b11111:                             //F800 (sound)
		endcase
end

//IRQ
reg [15:0] count;
wire [15:0] count_next=count+1'd1;
wire countup=count[15] & ~&count[14:0];
reg timeout;
assign irq=timeout;
always@(posedge clk20) begin
if (SaveStateBus_load) begin
	count   <= SS_MAP3[23: 8];
	timeout <= SS_MAP3[   24];
end else if (ce) begin
	if(prgain[15:12]==4'b0101)
		timeout<=0;
	else if(count==16'hFFFF)
		timeout<=1;

	if(nesprg_we & prgain[15:11]==5'b01010)
		count[7:0]<=nesprgdin;
	else if(countup)
		count[7:0]<=count_next[7:0];

	if(nesprg_we & prgain[15:11]==5'b01011)
		count[15:8]<=nesprgdin;
	else if(countup)
		count[15:8]<=count_next[15:8];
	end
end

assign SS_MAP1_BACK[ 7: 0] = chr0;
assign SS_MAP1_BACK[15: 8] = chr1;
assign SS_MAP1_BACK[23:16] = chr2;
assign SS_MAP1_BACK[31:24] = chr3;
assign SS_MAP1_BACK[39:32] = chr4;
assign SS_MAP1_BACK[47:40] = chr5;
assign SS_MAP1_BACK[55:48] = chr6;
assign SS_MAP1_BACK[63:56] = chr7;

assign SS_MAP2_BACK[15: 0] = 16'b0; // free to be used
assign SS_MAP2_BACK[23:16] = chr10;
assign SS_MAP2_BACK[31:24] = chr11;
assign SS_MAP2_BACK[39:32] = chr12;
assign SS_MAP2_BACK[47:40] = chr13;
assign SS_MAP2_BACK[49:48] = chr_en;
assign SS_MAP2_BACK[55:50] = prg89;
assign SS_MAP2_BACK[61:56] = prgAB;
assign SS_MAP2_BACK[63:62] = 2'b0; // free to be used

assign SS_MAP3_BACK[ 5: 0] = prgCD;
assign SS_MAP3_BACK[ 7: 6] = mirror;
assign SS_MAP3_BACK[23: 8] = count;
assign SS_MAP3_BACK[   24] = timeout;
assign SS_MAP3_BACK[63:25] = 39'b0; // free to be used

//PRG bank
reg [18:13] prgbankin;
always@* begin
	case(prgain[14:13])
		0:prgbankin=prg89;
		1:prgbankin=prgAB;
		2:prgbankin=prgCD;
		3:prgbankin=6'b111111;
	endcase
end

assign ramprgaout[18:13]=prgbankin[18:13] & cfg_prgmask & {4'b1111,{2{prgain[15]}}};

//CHR control
reg chrram;
reg [17:10] chrbank;
always@* begin
	case(chrain[13:10])
		0:chrbank=chr0;
		1:chrbank=chr1;
		2:chrbank=chr2;
		3:chrbank=chr3;
		4:chrbank=chr4;
		5:chrbank=chr5;
		6:chrbank=chr6;
		7:chrbank=chr7;
		8,12:chrbank=chr10;
		9,13:chrbank=chr11;
		10,14:chrbank=chr12;
		11,15:chrbank=chr13;
	endcase

	chrram=(~(chrain[12]?chr_en[1]:chr_en[0]))&(&chrbank[17:15]);   //ram/rom select

	if(!chrain[13]) begin
		ciram_ce=chrram && ~mapper210;
		chrram_oe=neschr_rd;
		chrram_we=neschr_wr & chrram;
		ramchraout[10]=chrbank[10];
	end else begin
		ciram_ce=(&chrbank[17:15]) | mapper210;
		chrram_oe=~ciram_ce & neschr_rd;
		chrram_we=~ciram_ce & neschr_wr & chrram;
		casez({mapper210,submapper1,mirror,cfg_vertical})
			5'b0?_??_?: ramchraout[10] = chrbank[10];
			//5'b0?_?1_?: ramchraout[10] = chrain[10];
			5'b10_00_?: ramchraout[10] = 1'b0;
			5'b10_01_?: ramchraout[10] = chrain[10];
			5'b10_10_?: ramchraout[10] = chrain[11];
			5'b10_11_?: ramchraout[10] = 1'b1;
			5'b11_??_0: ramchraout[10] = chrain[11];
			5'b11_??_1: ramchraout[10] = chrain[10];
		endcase
	end
	ramchraout[11]=chrbank[11];
	ramchraout[17:12]=chrbank[17:12] & cfg_chrmask[17:12];
	ramchraout[18]=ciram_ce;
end

assign wram_oe=m2_n & ~nesprg_we & prgain[15:13]==3'b011;
assign wram_we=m2_n &  nesprg_we & prgain[15:13]==3'b011;

assign prgram_we=0;
assign prgram_oe= ~cfg_boot & m2_n & ~nesprg_we & prgain[15];

wire config_rd = 0;
//wire [7:0] gg_out;
//gamegenie gg(m2, reset, nesprg_we, prgain, nesprgdin, ramprgdin, gg_out, config_rd);

//PRG data out
wire mapper_oe = m2_n & ~nesprg_we & ((prgain[15:12]=='b0101) || (prgain[15:11]=='b01001));
always @* begin
	case(prgain[15:11])
		5'b01001: nesprgdout=audio_dout;
		5'b01010: nesprgdout=count[7:0];
		5'b01011: nesprgdout=count[15:8];
		default: nesprgdout=nesprgdin;
	endcase
end

assign nesprg_oe=wram_oe | prgram_oe | mapper_oe | config_rd;

assign neschr_oe=0;
assign neschrdout=0;

// savestate
localparam SAVESTATE_MODULES    = 3;
wire [63:0] SaveStateBus_wired_or[0:SAVESTATE_MODULES-1];
wire [63:0] SS_MAP1, SS_MAP2, SS_MAP3;
wire [63:0] SS_MAP1_BACK, SS_MAP2_BACK, SS_MAP3_BACK;	
wire [63:0] SaveStateBus_Dout_active = SaveStateBus_wired_or[0] | SaveStateBus_wired_or[1] | SaveStateBus_wired_or[2];
	
eReg_SavestateV #(SSREG_INDEX_MAP1, 64'h0000000000000000) iREG_SAVESTATE_MAP1 (clk20, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_wired_or[0], SS_MAP1_BACK, SS_MAP1);  
eReg_SavestateV #(SSREG_INDEX_MAP2, 64'h0000000000000000) iREG_SAVESTATE_MAP2 (clk20, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_wired_or[1], SS_MAP2_BACK, SS_MAP2);  
eReg_SavestateV #(SSREG_INDEX_MAP3, 64'h0000000000000000) iREG_SAVESTATE_MAP3 (clk20, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_wired_or[2], SS_MAP3_BACK, SS_MAP3);  

assign SaveStateBus_Dout = ~reset ? SaveStateBus_Dout_active : 64'h0000000000000000;

endmodule