Files
vhdl/lib/CPUs/JCpu/src/core/cpu.vhd
T
jens a2f631f4de - removed signal 'irq_out'
Committed on the Free edition of March Hare Software CVSNT Server.
Upgrade to CVS Suite for more features and support:
http://march-hare.com/cvsnt/


git-svn-id: http://moon:8086/svn/vhdl/trunk@922 cc03376c-175c-47c8-b038-4cd826a8556b
2011-06-25 15:28:08 +00:00

564 lines
13 KiB
VHDL

--------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: JCPU top file
--
-- 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 cpu is
Generic (
use_instr_register : boolean := false;
use_ctrl_rom : boolean := true
);
Port (
rst : in STD_LOGIC;
clk : in STD_LOGIC;
ce : in STD_LOGIC;
int_in : in STD_LOGIC;
int_ack : out STD_LOGIC;
xmem_we : out STD_LOGIC;
xmem_re : out STD_LOGIC;
instr_din : in unsigned (IMEM_DATA_WIDTH-1 downto 0);
instr_addr : out unsigned (IMEM_ADDR_WIDTH-1 downto 0);
xmem_din : in unsigned (DMEM_DATA_WIDTH-1 downto 0);
xmem_dout : out unsigned (DMEM_DATA_WIDTH-1 downto 0);
xmem_addr : out unsigned (DMEM_ADDR_WIDTH-1 downto 0);
io_sel : out std_logic
);
end cpu;
architecture rtl of cpu is
COMPONENT stack_ctrl
GENERIC (
addr_width : integer
);
Port (
rst : in STD_LOGIC;
clk : in STD_LOGIC;
push : in STD_LOGIC;
pop : in STD_LOGIC;
din : in inst_addr_t;
dout : out inst_addr_t;
mem_we : out STD_LOGIC;
ptr_out : out unsigned (addr_width-1 downto 0)
);
END COMPONENT;
COMPONENT pc
Port (
rst : in STD_LOGIC;
clk : in STD_LOGIC;
inc : in STD_LOGIC;
load : in STD_LOGIC;
pc_in : in inst_addr_t;
pc_out : out inst_addr_t;
pc_next : out inst_addr_t
);
END COMPONENT;
COMPONENT dpath_ctrl
GENERIC (
use_rom : boolean
);
Port (
inst_in : in inst_t;
iphase_in : in iphase_t;
status_in : in cpu_status_t;
ctrl_out : out dpath_ctrl_out_t;
idout : out inst_addr_t;
ddout : out dmem_data_t
);
END COMPONENT;
COMPONENT int_ctrl
Port (
rst : in STD_LOGIC;
clk : in STD_LOGIC;
ctrl_in : in int_ctrl_in_t;
int_in : in STD_LOGIC;
int_exit : in STD_LOGIC;
iphase_in : in iphase_t;
int_ack_out : out STD_LOGIC;
stat_save_out : out STD_LOGIC;
stat_rest_out : out STD_LOGIC;
pc_addr_out : out inst_addr_t;
pc_load_out : out STD_LOGIC;
stk_push_out : out STD_LOGIC;
stk_pop_out : out STD_LOGIC
);
END COMPONENT;
COMPONENT reg_dual
GENERIC (
addr_width : integer;
data_width : integer
);
Port (
clk : in STD_LOGIC;
we_a : in STD_LOGIC;
ptr_a : in reg_ptr_t;
ptr_b : in reg_ptr_t;
din_a : in unsigned (data_width-1 downto 0);
dout_a : out unsigned (data_width-1 downto 0);
dout_b : out unsigned (data_width-1 downto 0)
);
END COMPONENT;
COMPONENT chipram
GENERIC (
addr_width : integer;
data_width : integer
);
Port (
clka : in STD_LOGIC;
clkb : in STD_LOGIC;
en_a : in STD_LOGIC;
en_b : in STD_LOGIC;
we_a : in STD_LOGIC;
we_b : in STD_LOGIC;
addr_a : in unsigned (addr_width-1 downto 0);
addr_b : in unsigned (addr_width-1 downto 0);
din_a : in unsigned (data_width-1 downto 0);
din_b : in unsigned (data_width-1 downto 0);
dout_a : out unsigned (data_width-1 downto 0);
dout_b : out unsigned (data_width-1 downto 0)
);
END COMPONENT;
COMPONENT chipreg
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 COMPONENT;
COMPONENT alu
GENERIC (
data_width : integer := 8
);
Port (
rst : in STD_LOGIC;
clk : in STD_LOGIC;
op_en : in STD_LOGIC;
cy_in : in STD_LOGIC;
op1_in : in unsigned (data_width-1 downto 0);
op2_in : in unsigned (data_width-1 downto 0);
opsel : in alu_op_t;
res_out : out unsigned (data_width-1 downto 0);
stat_load : in STD_LOGIC;
stat_in : in alu_status_t;
stat_out : out alu_status_t
);
END COMPONENT;
signal cpu_status, status_reg : cpu_status_t; -- := cpu_status_t(others => '0');
signal ctrl : dpath_ctrl_out_t;
signal stk_out : inst_addr_t;
signal stk_in : inst_addr_t;
signal stk_reg : inst_addr_t;
signal pc_in, pc_out, pc_next, idata, int_pc_addr : inst_addr_t;
signal iphase : iphase_t;
signal const_data, reg_a_dout, reg_b_dout : dmem_data_t;
signal reg_din : dmem_data_t;
signal alu_op1, alu_op2, alu_result : dmem_data_t;
signal alu_status : alu_status_t;
signal pc_inc, pc_load, cpu_active, stk_we, cmem_we, creg_we : STD_LOGIC;
signal ctrl_inst : inst_t;
signal ctrl_iphase : iphase_t;
signal was_pcld, was_pop2pc, int_pc_load, int_stk_push, int_stk_pop, stk_push, stk_pop : STD_LOGIC;
signal status_save, status_restore : STD_LOGIC;
signal creg_dout : dmem_data_t;
signal cmem_din, cmem_dout : inst_addr_t;
signal stk_addr, cmem_addr : unsigned(CHIPRAM_SIZE_BITS-1 downto 0);
signal stk_ptr : unsigned(STACK_SIZE_BITS-1 downto 0);
signal creg_ctrl_out : creg_ctrl_out_t;
signal creg_ctrl_in : creg_ctrl_in_t;
signal xio_sel, cio_sel : std_logic;
signal mem_data : dmem_data_t;
signal mem_addr : dmem_data_t;
begin
io_sel <= xio_sel;
instr_addr <= pc_out;
pc_inc <= cpu_active and ctrl.lines.pc_inc;
stk_addr <= '0' & stk_ptr;
cpu_status.alu <= alu_status;
creg_ctrl_in.alu <= alu_status;
xmem_dout <= mem_data;
xmem_addr <= mem_addr;
cmem_din <= creg_ctrl_out.cmem_high & mem_data;
cmem_addr <= '1' & creg_ctrl_out.bank_sel & mem_addr(MIN(cmem_addr'length-creg_ctrl_out.bank_sel'length-1, mem_addr'length)-1 downto 0);
--------------------------------------------------------------------
mem_ctrl_lines:
process(ctrl.lines)
begin
xio_sel <= '0';
xmem_re <= '0';
xmem_we <= '0';
cio_sel <= '0';
cmem_we <= '0';
creg_we <= '0';
case ctrl.lines.mem_access is
when xmem_access =>
xmem_re <= ctrl.lines.mem_read;
xmem_we <= ctrl.lines.mem_write;
when xio_access =>
xio_sel <= '1';
xmem_re <= ctrl.lines.mem_read;
xmem_we <= ctrl.lines.mem_write;
when cmem_access =>
cmem_we <= ctrl.lines.mem_write;
when cio_access =>
cio_sel <= '1';
creg_we <= ctrl.lines.mem_write;
when others => null;
end case;
end process;
iphase_counter:
process(rst, clk, ce)
variable pos : integer;
begin
if rst = '1' then
iphase <= iphase_t'low;
cpu_active <= '0';
elsif rising_edge(clk) then
cpu_active <= '0';
if ce = '1' then
cpu_active <= '1';
if iphase = iphase_t'high then
iphase <= iphase_t'low;
else
iphase <= iphase + 1;
end if;
end if;
end if;
end process;
gen_instr_reg:
if use_instr_register = true generate
instr_reg:
process (rst, clk, ce)
begin
if rst = '1' then
ctrl_inst <= (others => '0');
ctrl_iphase <= 0;
elsif rising_edge(clk) and ce = '1' then
ctrl_inst <= instr_din;
ctrl_iphase <= iphase;
end if;
end process;
end generate;
gen_instr_direct:
if use_instr_register = false generate
ctrl_inst <= instr_din;
ctrl_iphase <= iphase;
end generate;
status_register:
process(clk, status_save)
begin
if rising_edge(clk) and status_save = '1' then
status_reg.alu <= alu_status;
end if;
end process;
pc_pushpop:
process(ctrl.lines, int_pc_load, int_stk_push, int_stk_pop, was_pop2pc)
begin
pc_load <= ctrl.lines.pc_load or int_pc_load;
stk_push <= ctrl.lines.stk_push or (int_stk_push and not was_pop2pc);
stk_pop <= (ctrl.lines.stk_pop and not ctrl.lines.pc_load) or int_stk_pop or ((ctrl.lines.stk_pop and ctrl.lines.pc_load) and not int_pc_load);
end process;
lines_delay:
process(clk)
begin
if rising_edge(clk) then
was_pcld <= ctrl.lines.pc_load;
was_pop2pc <= ctrl.lines.stk_pop and ctrl.lines.pc_load;
end if;
end process;
stk_mux:
process(ctrl.lines, was_pcld, int_stk_push, pc_next, idata, reg_a_dout, creg_ctrl_out)
begin
if was_pcld = '1' and int_stk_push = '1' then
stk_in <= idata;
elsif ctrl.lines.stk_push = '1' and ctrl.lines.pc_load = '0' then
stk_in <= creg_ctrl_out.stk_high & reg_a_dout;
else
stk_in <= pc_next;
end if;
end process;
pc_mux:
process(ctrl.lines, int_pc_load, int_stk_pop, idata, int_pc_addr, stk_out)
begin
pc_in <= stk_out;
if int_pc_load = '1' then
if int_stk_pop = '0' then
pc_in <= int_pc_addr;
end if;
elsif ctrl.lines.pc_load = '1' then
if ctrl.lines.stk_pop = '0' then
pc_in <= idata;
end if;
end if;
end process;
mem_data_mux:
process(ctrl.lines.ddata_src_sel, reg_a_dout, reg_b_dout, const_data, creg_ctrl_out)
begin
case ctrl.lines.ddata_src_sel is
when reg_a =>
mem_data <= reg_a_dout;
when reg_b =>
mem_data <= reg_b_dout;
when const =>
mem_data <= const_data;
when others =>
mem_data <= const_data;
end case;
end process;
mem_addr_mux:
process(ctrl.lines.daddr_src_sel, reg_a_dout, reg_b_dout, const_data, creg_ctrl_out.bank_sel)
begin
case ctrl.lines.daddr_src_sel is
when reg_a =>
mem_addr <= reg_a_dout;
when reg_b =>
mem_addr <= reg_b_dout;
when const =>
mem_addr <= const_data;
when others =>
mem_addr <= const_data;
end case;
end process;
reg_in_mux:
process(ctrl.lines.reg_src_sel, cio_sel, xmem_din, alu_result, stk_out, cmem_dout, creg_dout)
variable data : dmem_data_t;
begin
case ctrl.lines.reg_src_sel is
when xmem_src =>
data := xmem_din;
when cmem_src =>
if cio_sel = '0' then
data := cmem_dout(dmem_data_t'range);
else
data := creg_dout(dmem_data_t'range);
end if;
when stk_src =>
data := stk_out(dmem_data_t'range);
when others =>
data := alu_result;
end case;
reg_din <= data;
end process;
alu_op1_mux:
process(ctrl.lines.alu_op1_src_sel, reg_a_dout, reg_b_dout, const_data)
variable data : dmem_data_t;
begin
case ctrl.lines.alu_op1_src_sel is
when reg_a =>
data := reg_a_dout;
when reg_b =>
data := reg_b_dout;
when others =>
data := const_data;
end case;
alu_op1 <= data;
end process;
alu_op2_mux:
process(ctrl.lines.alu_op2_src_sel, reg_a_dout, reg_b_dout, const_data)
variable data : dmem_data_t;
begin
case ctrl.lines.alu_op2_src_sel is
when reg_a =>
data := reg_a_dout;
when reg_b =>
data := reg_b_dout;
when others =>
data := const_data;
end case;
alu_op2 <= data;
end process;
--------------------------------------------------------------------
inst_stack_ctrl: stack_ctrl
GENERIC MAP (
addr_width => STACK_SIZE_BITS
)
PORT MAP(
rst => rst,
clk => clk,
push => stk_push,
pop => stk_pop,
dout => stk_reg,
din => stk_in,
ptr_out => stk_ptr,
mem_we => stk_we
);
inst_pc: pc
PORT MAP(
rst => rst,
clk => clk,
inc => pc_inc,
load => pc_load,
pc_in => pc_in,
pc_out => pc_out,
pc_next => pc_next
);
inst_dpath_ctrl: dpath_ctrl
GENERIC MAP (
use_rom => use_ctrl_rom
)
PORT MAP(
inst_in => ctrl_inst,
iphase_in => ctrl_iphase,
status_in => cpu_status,
ctrl_out => ctrl,
ddout => const_data,
idout => idata
);
inst_int_ctrl: int_ctrl
PORT MAP(
rst => rst,
clk => clk,
ctrl_in => creg_ctrl_out.int_ctrl,
int_in => int_in,
int_ack_out => int_ack,
int_exit => ctrl.lines.int_exit,
iphase_in => ctrl_iphase,
stat_save_out => status_save,
stat_rest_out => status_restore,
pc_addr_out => int_pc_addr,
pc_load_out => int_pc_load,
stk_push_out => int_stk_push,
stk_pop_out => int_stk_pop
);
inst_reg_ab: reg_dual
GENERIC MAP (
addr_width => REG_SIZE_BITS,
data_width => DMEM_DATA_WIDTH
)
PORT MAP(
clk => clk,
we_a => ctrl.lines.reg_we,
ptr_a => ctrl.reg_a_ptr,
ptr_b => ctrl.reg_b_ptr,
din_a => reg_din,
dout_a => reg_a_dout,
dout_b => reg_b_dout
);
inst_chipram: chipram
GENERIC MAP (
addr_width => CHIPRAM_SIZE_BITS,
data_width => IMEM_ADDR_WIDTH
)
PORT MAP(
clka => clk,
clkb => clk,
en_a => cpu_active,
en_b => cpu_active,
we_a => stk_we,
we_b => cmem_we,
addr_a => stk_addr,
addr_b => cmem_addr,
din_a => stk_reg,
din_b => cmem_din,
dout_a => stk_out,
dout_b => cmem_dout
);
inst_chipreg: chipreg
PORT MAP(
rst => rst,
clk => clk,
we => creg_we,
addr => mem_addr,
din => mem_data,
dout => creg_dout,
ctrl_in => creg_ctrl_in,
ctrl_out => creg_ctrl_out
);
inst_alu: alu
GENERIC MAP (
data_width => DMEM_DATA_WIDTH
)
PORT MAP(
rst => rst,
clk => clk,
op_en => ctrl.lines.alu_load,
cy_in => ctrl.lines.alu_cy_in,
op1_in => alu_op1,
op2_in => alu_op2,
opsel => ctrl.lines.alu_opsel,
res_out => alu_result,
stat_load => status_restore,
stat_in => status_reg.alu,
stat_out => alu_status
);
end rtl;