--  The!Cart type and address definitions
--
--  Copyright (C) 2011-2014 Matthias Reichl <hias@horus.com>
--
--  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 2 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, write to the Free Software
--  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


library IEEE;
use IEEE.STD_LOGIC_1164.all;

package CartDef is

	subtype vec4 is std_logic_vector(3 downto 0);
	subtype vec8 is std_logic_vector(7 downto 0);
	subtype vec12 is std_logic_vector(12 downto 0);
	subtype vec27 is std_logic_vector(26 downto 0);
	subtype bankvec is std_logic_vector(26 downto 13);

	type CartControlState is (no_cctl_access, access_cctl_thecart, access_cctl_emulated);
	
	type data_output is
	record
		dout: vec8;
		dout_enable: boolean;
	end record;

	type cart_mem_output is
	record
		adr: vec27;
		ram_access: boolean;
		rom_access: boolean;
		rd4: boolean;
		rd5: boolean;
	end record;
	
	function "or"(a: cart_mem_output; b: cart_mem_output) return cart_mem_output;
	function "or"(a: data_output; b: data_output) return data_output;
	
	-- bank 0
	constant startup_bank: 	        bankvec	:= "00000000000000";
	
	-- addresses in CCTL page
	
	-- base 16-byte block within CCTL page (bits 7-4)
	constant cfg_base_adr: vec8 := x"A0";
	
	-- D5A0 - bank select (bits 0-7)
	-- D5A1 - bank select (bits 8-13)
	-- writing these registers also enables cart (cfg_enable/D5A2)
	constant cfg_bank_adr_lo: vec4 := x"0";
	constant cfg_bank_adr_hi: vec4 := x"1";

	-- D5A2 - cart enable
	-- bit 7..1: reserved
	-- bit 0: 0=disable 1=enable
	constant cfg_enable_adr: vec4 := x"2";

	-- D5A3 - secondary bank select (bits 0-7)
	-- D5A4 - secondary bank select (bits 8-13)
	-- writing this register also enables cart (cfg_enable2/D5A5)
	constant cfg_bank2_adr_lo: vec4 := x"3";
	constant cfg_bank2_adr_hi: vec4 := x"4";

	-- D5A5 - secondary bank enable
	-- bit 7..1: reserved
	-- bit 0: 0=disable 1=enable
	constant cfg_enable2_adr: vec4 := x"5";

	-- D5A6 - cart mode
	-- bit 7..6: reserved
	-- bit 5..0: mode select
	constant cfg_mode_adr: vec4 := x"6";

	-- D5A7 - misc config
	-- bit 7..4: reserved
	-- bit 3: secondary bank: 0=ROM, 1=RAM
	-- bit 2: secondary bank: 0=write protect, 1=write enable
	-- bit 1: 0=ROM, 1=RAM
	-- bit 0: 0=write protect, 1=write enable
	constant cfg_misc_adr: vec4 := x"7";

	-- D5A8 - SPI in/out register
	-- bit 7: data in/out
	-- bit 6..2: reserved
	-- bit 1: cs
	-- bit 0: clk
	constant spi_adr: vec4 := x"8";

	-- D5AF - configuration lock register
	-- writing to this registers locks the current
	-- configuration and disables thecart registers at $Ax
	constant cfg_lock_adr: vec4 := x"F";

end CartDef;


package body CartDef is

function "or"(a: cart_mem_output; b: cart_mem_output) return cart_mem_output is
variable r: cart_mem_output;
begin
	r.adr := a.adr or b.adr;
	r.ram_access := a.ram_access or b.ram_access;
	r.rom_access := a.rom_access or b.rom_access;
	r.rd4 := a.rd4 or b.rd4;
	r.rd5 := a.rd5 or b.rd5;
	return r;
end "or";

function "or"(a: data_output; b: data_output) return data_output is
variable r: data_output;
begin
	r.dout := a.dout or b.dout;
	r.dout_enable := a.dout_enable or b.dout_enable;
	return r;
end "or";

end CartDef;
