module SachenJV001(
	input        clk,         // System clock
	input        ce,          // M2 ~cpu_clk
	input        enable,      // Mapper enabled
	input [31:0] flags,       // Cart flags
	input [15:0] prg_ain,     // prg address
	inout [21:0] prg_aout_b,  // prg address out
	input        prg_read,    // prg read
	input        prg_write,   // prg write
	input  [7:0] prg_din,     // prg data in
	inout  [7:0] prg_dout_b,  // prg data out
	inout        prg_allow_b, // Enable access to memory for the specified operation.
	input [13:0] chr_ain,     // chr address in
	inout [21:0] chr_aout_b,  // chr address out
	input        chr_read,    // chr ram read
	inout        chr_allow_b, // chr allow write
	inout        vram_a10_b,  // Value for A10 address line
	inout        vram_ce_b,   // True if the address should be routed to the internal 2kB VRAM.
	inout        irq_b,       // IRQ
	input [15:0] audio_in,    // Inverted audio from APU
	inout [15:0] audio_b,     // Mixed audio output
	inout [15:0] flags_out_b, // flags {0, 0, 0, 0, has_savestate, prg_conflict, prg_bus_write, has_chr_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 prg_aout_b   = enable ? prg_aout : 22'hZ;
assign prg_dout_b   = enable ? prg_dout : 8'hZ;
assign prg_allow_b  = enable ? prg_allow : 1'hZ;
assign chr_aout_b   = enable ? chr_aout : 22'hZ;
assign chr_allow_b  = enable ? chr_allow : 1'hZ;
assign vram_a10_b   = enable ? vram_a10 : 1'hZ;
assign vram_ce_b    = enable ? vram_ce : 1'hZ;
assign irq_b        = enable ? 1'b0 : 1'hZ;
assign flags_out_b  = enable ? flags_out : 16'hZ;
assign audio_b      = enable ? {1'b0, audio_in[15:1]} : 16'hZ;

wire [21:0] prg_aout, chr_aout;
wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
wire [15:0] flags_out = {12'd0, 1'b1, 1'b0, prg_bus_write, 1'b0};

reg [5:0] input_reg; //s_reg = input_reg[3]
reg [5:0] output_reg;
reg [5:0] register_reg;
reg inc_reg;
reg invert_reg;
reg [3:0] alt_chr;
reg mirroring;

//wire mapper136 = (flags[7:0] == 136); //default
wire mapper132 = (flags[7:0] == 132);
wire mapper147 = (flags[7:0] == 147);
wire mapper173 = (flags[7:0] == 173);
wire mapper172 = (flags[7:0] == 172);
wire mapper36  = (flags[7:0] == 36);

wire [7:0] prg_din_adj = mapper147 ? {2'b00, prg_din[7:2]} :
                         mapper36 ?  {4'b0000, prg_din[7:4]} : 
								 mapper172 ? {2'b00, prg_din[0], prg_din[1], prg_din[2], prg_din[3], prg_din[4], prg_din[5]} :
								             prg_din;

wire prg_bus_write = (prg_ain[15:13] == 3'b010 && prg_ain[8]); //0x4100-3

always @(posedge clk)
if (~enable) begin
	//
end else if (SaveStateBus_load) begin
	input_reg   <= SS_MAP1[ 5: 0];
	output_reg  <= SS_MAP1[11: 6];
	register_reg<= SS_MAP1[17:12];
	inc_reg     <= SS_MAP1[   18];
	invert_reg  <= SS_MAP1[   19];
	alt_chr     <= SS_MAP1[23:20];
	mirroring   <= SS_MAP1[   24];
end else if (ce) begin
	if (prg_ain[15:13] == 3'b010 && prg_ain[8] && prg_write) //0x4100-3
		case (prg_ain[1:0])
			0: begin
				if (inc_reg)
					register_reg[3:0] <= register_reg[3:0] + 4'b1;
				else
					register_reg <= invert_reg ? {input_reg[5:4], ~input_reg[3:0]} : input_reg;
			   end
			1: invert_reg <= prg_din_adj[0];
			2: input_reg  <= prg_din_adj[5:0];
			3: inc_reg    <= prg_din_adj[0];
		endcase
	if (prg_ain[15:13] == 3'b010 && prg_ain[9] && prg_write) //0x4200
		alt_chr <= prg_din[3:0];
	if (prg_ain[15] == 1'b1 && prg_write) begin
		output_reg <= register_reg;
		mirroring <= invert_reg;
	end
end

assign SS_MAP1_BACK[ 5: 0] = input_reg;
assign SS_MAP1_BACK[11: 6] = output_reg;
assign SS_MAP1_BACK[17:12] = register_reg;
assign SS_MAP1_BACK[   18] = inc_reg;
assign SS_MAP1_BACK[   19] = invert_reg;
assign SS_MAP1_BACK[23:20] = alt_chr;
assign SS_MAP1_BACK[   24] = mirroring;
assign SS_MAP1_BACK[63:25] = 39'b0; // free to be used

// 0x4100-3
wire use_s = mapper132 | mapper173;
wire [5:0] V001_val = (use_s ? {2'b00, input_reg[3], register_reg[2:0]} : register_reg) ^ (invert_reg ? (use_s ? 6'h08 : 6'h30) : 6'h00);

wire [7:0] prg_dout = mapper172 ? {chr_ain[7:6], V001_val[0], V001_val[1], V001_val[2], V001_val[3], V001_val[4], V001_val[5]} :
                      mapper147 ? {V001_val, chr_ain[1:0]} :
							             {chr_ain[7:6], V001_val}; // two bits are open bus

wire [3:0] chr_sel = mapper36 ? alt_chr :
                     mapper173 ? {2'b00, ~invert_reg, output_reg[0]} :
							mapper147 ? {output_reg[4:1]} :
							mapper172 ? {2'b00, output_reg[1:0]} :
							            {2'b00, output_reg[1:0]};

wire [1:0] prg_sel = mapper147 ? {output_reg[5], output_reg[0]} :
                     mapper132 ? {1'b0, output_reg[2]} :
							mapper36  ? {output_reg[1:0]} :
							            2'b00;

assign prg_aout = {5'b00_000, prg_sel, prg_ain[14:0]};
assign prg_allow = prg_ain[15] && !prg_write;
assign chr_allow = flags[15];
assign chr_aout = {5'b10_000, chr_sel, chr_ain[12:0]};
assign vram_ce = chr_ain[13];
assign vram_a10 = (mapper172 ? mirroring : flags[14]) ? chr_ain[10] : chr_ain[11]; // 0: horiz, 1: vert

// savestate
wire [63:0] SS_MAP1;
wire [63:0] SS_MAP1_BACK;	
wire [63:0] SaveStateBus_Dout_active;	
eReg_SavestateV #(SSREG_INDEX_MAP1, 64'h0000000000000000) iREG_SAVESTATE_MAP1 (clk, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_Dout_active, SS_MAP1_BACK, SS_MAP1);  

assign SaveStateBus_Dout = enable ? SaveStateBus_Dout_active : 64'h0000000000000000;

endmodule