Initial import
git-svn-id: http://moon:8086/svn/vhdl/trunk@2 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
@@ -0,0 +1,566 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- 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_wait : in 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 irq_out : std_logic;
|
||||
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;
|
||||
cpu_status.xmem_wait <= xmem_wait;
|
||||
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.page_sel & mem_addr(MIN(cmem_addr'length-creg_ctrl_out.page_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_pushd or ctrl.lines.stk_push) or (int_stk_push and not was_pop2pc);
|
||||
stk_pop <= ctrl.lines.stk_popd or int_stk_pop or (ctrl.lines.stk_pop 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_pushd = '1' 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.page_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;
|
||||
Reference in New Issue
Block a user