mirror of
https://github.com/j-core/j-core-ice40.git
synced 2026-01-11 23:52:49 +00:00
200 lines
6.1 KiB
VHDL
200 lines
6.1 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
use work.decode_pack.all;
|
|
use work.cpu2j0_pack.all;
|
|
use work.predecode_pack.all;
|
|
|
|
entity decode_core is
|
|
generic (
|
|
-- decode_type : cpu_decode_type_t := REVERSE;
|
|
-- reset_vector : decode_core_reg_t := DEC_CORE_RESET);
|
|
-- ROM
|
|
-- decode_type : cpu_decode_type_t := MICROCODE;
|
|
-- reset_vector : decode_core_reg_t := DEC_CORE_ROM_RESET);
|
|
-- staircase
|
|
decode_type : cpu_decode_type_t := SIMPLE;
|
|
reset_vector : decode_core_reg_t := DEC_CORE_RESET);
|
|
port (
|
|
clk : in std_logic;
|
|
delay_jump : in std_logic;
|
|
dispatch : in std_logic;
|
|
event_ack_0 : in std_logic;
|
|
event_i : in cpu_event_i_t;
|
|
ex : in pipeline_ex_t;
|
|
ex_stall : in pipeline_ex_stall_t;
|
|
ibit : in std_logic_vector(3 downto 0);
|
|
id : in pipeline_id_t;
|
|
if_dr : in std_logic_vector(15 downto 0);
|
|
if_stall : in std_logic;
|
|
ilevel_cap : in std_logic;
|
|
illegal_delay_slot : in std_logic;
|
|
illegal_instr : in std_logic;
|
|
mac_busy : in std_logic;
|
|
mac_stall_sense : in std_logic;
|
|
maskint_next : in std_logic;
|
|
p : in pipeline_t;
|
|
rst : in std_logic;
|
|
slot : in std_logic;
|
|
t_bcc : in std_logic;
|
|
debug : in std_logic;
|
|
enter_debug : in std_logic;
|
|
event_ack : out std_logic;
|
|
if_issue : out std_logic;
|
|
ifadsel : out std_logic;
|
|
ilevel : out std_logic_vector(3 downto 0);
|
|
incpc : out std_logic;
|
|
op : out operation_t;
|
|
next_id_stall : out std_logic
|
|
);
|
|
end;
|
|
|
|
architecture arch of decode_core is
|
|
signal mac_stall : std_logic;
|
|
signal reg_conf : std_logic;
|
|
signal next_op : operation_t;
|
|
signal instr_state_sel : std_logic;
|
|
signal next_id_stall_a : std_logic;
|
|
signal maskint : std_logic;
|
|
signal delay_slot : std_logic;
|
|
|
|
signal this_c : decode_core_reg_t;
|
|
signal this_r : decode_core_reg_t := reset_vector;
|
|
|
|
function system_op (code : std_logic_vector(15 downto 0); instr : system_instr_t)
|
|
return operation_t is
|
|
variable vop : operation_t;
|
|
begin
|
|
vop.plane := SYSTEM_INSTR;
|
|
vop.code := code;
|
|
if decode_type = MICROCODE then
|
|
-- Microcode-based decoder requires an address into the ROM that is different
|
|
-- for each system instruction
|
|
vop.addr := system_instr_rom_addrs(instr);
|
|
else
|
|
vop.addr := x"00";
|
|
end if;
|
|
return vop;
|
|
end;
|
|
|
|
function system_op (instr : system_instr_t)
|
|
return operation_t is
|
|
variable cd : std_logic_vector(15 downto 0);
|
|
begin
|
|
cd := x"0" & system_instr_codes(instr) & x"00";
|
|
return system_op(cd, instr);
|
|
end;
|
|
|
|
function system_op (event : cpu_event_i_t)
|
|
return operation_t is
|
|
variable code : std_logic_vector(15 downto 0);
|
|
begin
|
|
code := x"0" & system_event_codes(event.cmd) & event.vec;
|
|
return system_op(code, system_event_instrs(event.cmd));
|
|
end;
|
|
|
|
function normal_op (instr : std_logic_vector(15 downto 0))
|
|
return operation_t is
|
|
variable vop : operation_t;
|
|
begin
|
|
vop.plane := NORMAL_INSTR;
|
|
vop.code := instr;
|
|
if decode_type = MICROCODE then
|
|
-- Microcode-based decoder requires a first stage decode from the instruction
|
|
-- to the address in the ROM where the microcode starts for the instruction
|
|
vop.addr := predecode_rom_addr(instr);
|
|
else
|
|
vop.addr := x"00";
|
|
end if;
|
|
return vop;
|
|
end;
|
|
begin
|
|
|
|
decode_core_slot : process(this_r,slot,next_id_stall_a,ilevel_cap,dispatch,maskint_next,delay_jump,event_i,next_op)
|
|
variable this : decode_core_reg_t;
|
|
begin
|
|
this := this_r;
|
|
|
|
if slot = '1' then
|
|
this.maskint := maskint_next;
|
|
if ilevel_cap = '1' then
|
|
this.ilevel := event_i.lvl;
|
|
end if;
|
|
if this.id_stall = '0' and this.instr_seq_zero = '1' then
|
|
this.op := next_op;
|
|
end if;
|
|
this.id_stall := next_id_stall_a;
|
|
if next_id_stall_a = '0' then
|
|
this.delay_slot := delay_jump;
|
|
this.instr_seq_zero := dispatch;
|
|
this.op.addr := std_logic_vector(unsigned(this.op.addr) + 1);
|
|
end if;
|
|
end if;
|
|
|
|
this_c <= this;
|
|
end process;
|
|
|
|
decode_core_r0 : process(clk, rst)
|
|
begin
|
|
if rst='1' then
|
|
this_r <= reset_vector;
|
|
elsif clk='1' and clk'event then
|
|
this_r <= this_c;
|
|
end if;
|
|
end process;
|
|
|
|
maskint <= this_r.maskint;
|
|
delay_slot <= this_r.delay_slot;
|
|
ilevel <= this_r.ilevel;
|
|
|
|
mac_stall <= mac_stall_sense and (p.wb1.mac_busy or p.wb2.mac_busy or
|
|
p.wb3.mac_busy or p.ex1.mac_busy or mac_busy);
|
|
|
|
-- Next ID STALL
|
|
next_id_stall_a <= reg_conf or if_stall or mac_stall;
|
|
next_id_stall <= next_id_stall_a;
|
|
|
|
incpc <= id.incpc and not(next_id_stall_a);
|
|
|
|
ifadsel <= id.ifadsel;
|
|
if_issue <= id.if_issue and not(reg_conf) and not(mac_stall);
|
|
|
|
-- Detect Exception Events
|
|
next_op <=
|
|
system_op(event_i)
|
|
-- Interrupts, (address) errors, reset and break
|
|
when delay_slot = '0' and event_i.en = '1' and (
|
|
( maskint = '0' and event_i.cmd = INT and ( ibit < event_i.lvl or event_i.msk = '1' ) )
|
|
-- or
|
|
-- ( event_i.cmd = ERR or event_i.cmd = RST or event_i.cmd = BREAK )
|
|
) else
|
|
-- Slot Illegal Instruction
|
|
system_op(SLOT_ILLEGAL_I)
|
|
when delay_slot = '1' and (illegal_delay_slot or illegal_instr) = '1' else
|
|
-- General Illegal Instruction
|
|
system_op(GENERAL_ILLEGAL_I)
|
|
when illegal_instr = '1' else
|
|
-- Break Instruction
|
|
system_op(BREAK_I)
|
|
when delay_slot = '0' and enter_debug = '1' else
|
|
-- Normal instruction
|
|
normal_op(if_dr);
|
|
|
|
event_ack <= '1' when slot = '1' and (event_ack_0 = '1' or (event_i.en = '1' and event_i.cmd = BREAK and debug = '1') ) else '0';
|
|
|
|
op <= this_r.op when this_r.id_stall = '1' or this_r.instr_seq_zero = '0'
|
|
else next_op;
|
|
|
|
-- Detect register conflict
|
|
reg_conf <=
|
|
'1' when
|
|
-- W bus write to register
|
|
(p.wb1_stall.wrreg_w = '1' and
|
|
((ex.xbus_sel = SEL_REG and ex.regnum_x = p.wb1.regnum_w) or
|
|
(ex.ybus_sel = SEL_REG and ex.regnum_y = p.wb1.regnum_w) or
|
|
(ex_stall.wrreg_z = '1' and ex.regnum_z = p.wb1.regnum_w) or
|
|
-- write to R0
|
|
(ex.aluiny_sel = SEL_R0 and p.wb1.regnum_w = "00000")))
|
|
else '0';
|
|
end;
|