--------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: On-Chip registers
--
-- Copyright (C) 2007 J. Ahrensfeld
--
-- 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/>.
--
-- For questions and ideas, please contact the author at jens@jayfield.org
--
--------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

use work.cpu_pkg.all;

entity chipreg is
	Port (
		rst			: in  STD_LOGIC; 
		clk			: in  STD_LOGIC;
		we			: in  STD_LOGIC;
		addr		: in  dmem_addr_t;
		din			: in  dmem_data_t;
		dout		: out dmem_data_t;
		ctrl_in		: in  creg_ctrl_in_t;
		ctrl_out	: out creg_ctrl_out_t
	);
end chipreg;

architecture Behavioral of chipreg is

	signal reg_bank_sel		: bank_sel_t;
	signal reg_int_ctrl		: int_ctrl_in_t;
	signal reg_stk_high		: unsigned(IMEM_ADDR_WIDTH-DMEM_ADDR_WIDTH-1 downto 0);
	signal reg_cmem_high	: unsigned(IMEM_ADDR_WIDTH-DMEM_ADDR_WIDTH-1 downto 0);

begin

proc_assign_ctrl_lines:
	process (clk)
	begin
		if rising_edge(clk) then
			ctrl_out.bank_sel	<= reg_bank_sel;
			ctrl_out.int_ctrl	<= reg_int_ctrl;
			ctrl_out.stk_high	<= reg_stk_high;
			ctrl_out.cmem_high	<= reg_cmem_high;
		end if;
	end process;

proc_reg_write:
	process (rst, clk)
	begin
		if rst = '1' then
			reg_stk_high <= (others => '0');
			reg_cmem_high <= (others => '0');
			reg_bank_sel <= (others => '0');
			reg_int_ctrl.enable		<= '0';
		elsif rising_edge(clk) then
			if we = '1' then
				case addr is
				when X"01" =>
					reg_bank_sel(bank_sel_t'range)	<= din(bank_sel_t'range);
				when X"03" =>
					reg_int_ctrl.enable		<= din(0);
				when X"04" =>
					reg_cmem_high <= din(IMEM_ADDR_WIDTH-DMEM_ADDR_WIDTH-1 downto 0);
				when X"05" =>
					reg_stk_high <= din(IMEM_ADDR_WIDTH-DMEM_ADDR_WIDTH-1 downto 0);
				when others => null;
				end case;
			end if;
		end if;
	end process;

proc_reg_read:
	process (clk)
	begin
		if rising_edge(clk) then
			case addr is
			when X"00" =>	-- Revison
				dout <= to_unsigned(REVISION, dmem_data_t'length);
			when X"01" =>	-- Control 0
				dout <= (7 downto bank_sel_t'length => '0') & reg_bank_sel;
			when X"02" =>	-- CPU status
				dout <= "000000" & ctrl_in.alu.carry & ctrl_in.alu.zero;
			when X"03" =>	-- Interrupt control
				dout <= "0000000" & reg_int_ctrl.enable;
			when X"04" =>	-- Upper stack bits out
				dout <= "0000" & reg_cmem_high;
			when X"05" =>	-- Upper cmem bits out
				dout <= "0000" & reg_stk_high;
			when others => 
				if addr(0) = '0' then
					dout <= X"DE";
				else
					dout <= X"AD";
				end if;
			end case;
			
		end if;
	end process;

end Behavioral;

