mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-09 22:19:09 +00:00
Merge pull request #434 from paulusmack/compliance
Improve architecture compliance
This commit is contained in:
2
Makefile
2
Makefile
@@ -74,7 +74,7 @@ core_files = decode_types.vhdl common.vhdl wishbone_types.vhdl fetch1.vhdl \
|
||||
cr_file.vhdl crhelpers.vhdl ppc_fx_insns.vhdl rotator.vhdl \
|
||||
logical.vhdl countbits.vhdl multiply.vhdl multiply-32s.vhdl divider.vhdl \
|
||||
execute1.vhdl loadstore1.vhdl mmu.vhdl dcache.vhdl writeback.vhdl \
|
||||
core_debug.vhdl core.vhdl fpu.vhdl pmu.vhdl
|
||||
core_debug.vhdl core.vhdl fpu.vhdl pmu.vhdl bitsort.vhdl
|
||||
|
||||
soc_files = wishbone_arbiter.vhdl wishbone_bram_wrapper.vhdl sync_fifo.vhdl \
|
||||
wishbone_debug_master.vhdl xics.vhdl syscon.vhdl gpio.vhdl soc.vhdl \
|
||||
|
||||
102
bitsort.vhdl
Normal file
102
bitsort.vhdl
Normal file
@@ -0,0 +1,102 @@
|
||||
-- Implements instructions that involve sorting bits,
|
||||
-- that is, cfuged, pextd and pdepd.
|
||||
--
|
||||
-- cfuged: Sort the bits in the mask in RB into 0s at the left, 1s at the right
|
||||
-- and move the bits in RS in the same fashion to give the result
|
||||
-- pextd: Like cfuged but the only use the bits of RS where the
|
||||
-- corresponding bit in RB is 1
|
||||
-- pdepd: Inverse of pextd; take the low-order bits of RS and spread them out
|
||||
-- to the bit positions which have a 1 in RB
|
||||
|
||||
-- NB opc is bits 7-6 of the instruction:
|
||||
-- 00 = pdepd, 01 = pextd, 10 = cfuged
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.helpers.all;
|
||||
|
||||
entity bit_sorter is
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
rs : in std_ulogic_vector(63 downto 0);
|
||||
rb : in std_ulogic_vector(63 downto 0);
|
||||
go : in std_ulogic;
|
||||
opc : in std_ulogic_vector(1 downto 0);
|
||||
done : out std_ulogic;
|
||||
result : out std_ulogic_vector(63 downto 0)
|
||||
);
|
||||
end entity bit_sorter;
|
||||
|
||||
architecture behaviour of bit_sorter is
|
||||
|
||||
signal val : std_ulogic_vector(63 downto 0);
|
||||
signal st : std_ulogic;
|
||||
signal sd : std_ulogic;
|
||||
signal opr : std_ulogic_vector(1 downto 0);
|
||||
signal bc : unsigned(5 downto 0);
|
||||
signal jl : unsigned(5 downto 0);
|
||||
signal jr : unsigned(5 downto 0);
|
||||
signal sr_ml : std_ulogic_vector(63 downto 0);
|
||||
signal sr_mr : std_ulogic_vector(63 downto 0);
|
||||
signal sr_vl : std_ulogic_vector(63 downto 0);
|
||||
signal sr_vr : std_ulogic_vector(63 downto 0);
|
||||
|
||||
begin
|
||||
bsort_r: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
sd <= '0';
|
||||
if rst = '1' then
|
||||
st <= '0';
|
||||
opr <= "00";
|
||||
val <= (others => '0');
|
||||
elsif go = '1' then
|
||||
st <= '1';
|
||||
sr_ml <= rb;
|
||||
sr_mr <= rb;
|
||||
sr_vl <= rs;
|
||||
sr_vr <= rs;
|
||||
opr <= opc;
|
||||
val <= (others => '0');
|
||||
bc <= to_unsigned(0, 6);
|
||||
jl <= to_unsigned(63, 6);
|
||||
jr <= to_unsigned(0, 6);
|
||||
elsif st = '1' then
|
||||
if bc = 6x"3f" then
|
||||
st <= '0';
|
||||
sd <= '1';
|
||||
end if;
|
||||
bc <= bc + 1;
|
||||
if sr_ml(63) = '0' and opr(1) = '1' then
|
||||
-- cfuged
|
||||
val(to_integer(jl)) <= sr_vl(63);
|
||||
jl <= jl - 1;
|
||||
end if;
|
||||
if sr_mr(0) = '1' then
|
||||
if opr = "00" then
|
||||
-- pdepd
|
||||
val(to_integer(bc)) <= sr_vr(0);
|
||||
else
|
||||
-- cfuged or pextd
|
||||
val(to_integer(jr)) <= sr_vr(0);
|
||||
end if;
|
||||
jr <= jr + 1;
|
||||
end if;
|
||||
sr_vl <= sr_vl(62 downto 0) & '0';
|
||||
if opr /= "00" or sr_mr(0) = '1' then
|
||||
sr_vr <= '0' & sr_vr(63 downto 1);
|
||||
end if;
|
||||
sr_ml <= sr_ml(62 downto 0) & '0';
|
||||
sr_mr <= '0' & sr_mr(63 downto 1);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
done <= sd;
|
||||
result <= val;
|
||||
|
||||
end behaviour;
|
||||
109
common.vhdl
109
common.vhdl
@@ -12,6 +12,7 @@ package common is
|
||||
|
||||
-- MSR bit numbers
|
||||
constant MSR_SF : integer := (63 - 0); -- Sixty-Four bit mode
|
||||
constant MSR_HV : integer := (63 - 3); -- Hypervisor mode (always 1)
|
||||
constant MSR_EE : integer := (63 - 48); -- External interrupt Enable
|
||||
constant MSR_PR : integer := (63 - 49); -- PRoblem state
|
||||
constant MSR_FP : integer := (63 - 50); -- Floating Point available
|
||||
@@ -54,6 +55,15 @@ package common is
|
||||
constant SPR_PID : spr_num_t := 48;
|
||||
constant SPR_PTCR : spr_num_t := 464;
|
||||
constant SPR_PVR : spr_num_t := 287;
|
||||
constant SPR_FSCR : spr_num_t := 153;
|
||||
constant SPR_HFSCR : spr_num_t := 190;
|
||||
constant SPR_HEIR : spr_num_t := 339;
|
||||
constant SPR_CTRL : spr_num_t := 136;
|
||||
constant SPR_CTRLW : spr_num_t := 152;
|
||||
constant SPR_UDSCR : spr_num_t := 3;
|
||||
constant SPR_DSCR : spr_num_t := 17;
|
||||
constant SPR_VRSAVE : spr_num_t := 256;
|
||||
constant SPR_PIR : spr_num_t := 1023;
|
||||
|
||||
-- PMU registers
|
||||
constant SPR_UPMC1 : spr_num_t := 771;
|
||||
@@ -131,30 +141,52 @@ package common is
|
||||
constant RAMSPR_SPRG3 : ramspr_index := to_unsigned(3,3);
|
||||
constant RAMSPR_HSPRG1 : ramspr_index := to_unsigned(4,3);
|
||||
constant RAMSPR_CTR : ramspr_index := to_unsigned(5,3); -- must equal RAMSPR_LR
|
||||
constant RAMSPR_VRSAVE : ramspr_index := to_unsigned(6,3);
|
||||
|
||||
type ram_spr_info is record
|
||||
index : ramspr_index;
|
||||
isodd : std_ulogic;
|
||||
is32b : std_ulogic;
|
||||
valid : std_ulogic;
|
||||
end record;
|
||||
constant ram_spr_info_init: ram_spr_info := (index => to_unsigned(0,3), others => '0');
|
||||
|
||||
subtype spr_selector is std_ulogic_vector(2 downto 0);
|
||||
subtype spr_selector is std_ulogic_vector(3 downto 0);
|
||||
type spr_id is record
|
||||
sel : spr_selector;
|
||||
valid : std_ulogic;
|
||||
ispmu : std_ulogic;
|
||||
ronly : std_ulogic;
|
||||
wonly : std_ulogic;
|
||||
end record;
|
||||
constant spr_id_init : spr_id := (sel => "000", others => '0');
|
||||
constant spr_id_init : spr_id := (sel => "0000", others => '0');
|
||||
|
||||
constant SPRSEL_TB : spr_selector := 3x"0";
|
||||
constant SPRSEL_TBU : spr_selector := 3x"1";
|
||||
constant SPRSEL_DEC : spr_selector := 3x"2";
|
||||
constant SPRSEL_PVR : spr_selector := 3x"3";
|
||||
constant SPRSEL_LOGA : spr_selector := 3x"4";
|
||||
constant SPRSEL_LOGD : spr_selector := 3x"5";
|
||||
constant SPRSEL_CFAR : spr_selector := 3x"6";
|
||||
constant SPRSEL_XER : spr_selector := 3x"7";
|
||||
constant SPRSEL_TB : spr_selector := 4x"0";
|
||||
constant SPRSEL_TBU : spr_selector := 4x"1";
|
||||
constant SPRSEL_DEC : spr_selector := 4x"2";
|
||||
constant SPRSEL_PVR : spr_selector := 4x"3";
|
||||
constant SPRSEL_LOGA : spr_selector := 4x"4";
|
||||
constant SPRSEL_LOGD : spr_selector := 4x"5";
|
||||
constant SPRSEL_CFAR : spr_selector := 4x"6";
|
||||
constant SPRSEL_FSCR : spr_selector := 4x"7";
|
||||
constant SPRSEL_HFSCR : spr_selector := 4x"8";
|
||||
constant SPRSEL_HEIR : spr_selector := 4x"9";
|
||||
constant SPRSEL_CTRL : spr_selector := 4x"a";
|
||||
constant SPRSEL_DSCR : spr_selector := 4x"b";
|
||||
constant SPRSEL_PIR : spr_selector := 4x"c";
|
||||
constant SPRSEL_XER : spr_selector := 4x"f";
|
||||
|
||||
-- FSCR and HFSCR bit numbers
|
||||
constant FSCR_PREFIX : integer := 63 - 50;
|
||||
constant FSCR_SCV : integer := 63 - 51;
|
||||
constant FSCR_TAR : integer := 63 - 55;
|
||||
constant FSCR_DSCR : integer := 63 - 61;
|
||||
constant HFSCR_PREFIX : integer := 63 - 50;
|
||||
constant HFSCR_MSG : integer := 63 - 53;
|
||||
constant HFSCR_TAR : integer := 63 - 55;
|
||||
constant HFSCR_PMUSPR : integer := 63 - 60;
|
||||
constant HFSCR_DSCR : integer := 63 - 61;
|
||||
constant HFSCR_FP : integer := 63 - 63;
|
||||
|
||||
-- FPSCR bit numbers
|
||||
constant FPSCR_FX : integer := 63 - 32;
|
||||
@@ -224,14 +256,32 @@ package common is
|
||||
|
||||
-- This needs to die...
|
||||
type ctrl_t is record
|
||||
wait_state: std_ulogic;
|
||||
run: std_ulogic;
|
||||
tb: std_ulogic_vector(63 downto 0);
|
||||
dec: std_ulogic_vector(63 downto 0);
|
||||
msr: std_ulogic_vector(63 downto 0);
|
||||
cfar: std_ulogic_vector(63 downto 0);
|
||||
xer_low: std_ulogic_vector(17 downto 0);
|
||||
fscr_ic: std_ulogic_vector(3 downto 0);
|
||||
fscr_pref: std_ulogic;
|
||||
fscr_scv: std_ulogic;
|
||||
fscr_tar: std_ulogic;
|
||||
fscr_dscr: std_ulogic;
|
||||
hfscr_ic: std_ulogic_vector(3 downto 0);
|
||||
hfscr_pref: std_ulogic;
|
||||
hfscr_tar: std_ulogic;
|
||||
hfscr_dscr: std_ulogic;
|
||||
hfscr_fp: std_ulogic;
|
||||
heir: std_ulogic_vector(63 downto 0);
|
||||
dscr: std_ulogic_vector(24 downto 0);
|
||||
end record;
|
||||
constant ctrl_t_init : ctrl_t :=
|
||||
(xer_low => 18x"0", others => (others => '0'));
|
||||
(wait_state => '0', run => '1', xer_low => 18x"0",
|
||||
fscr_ic => x"0", fscr_pref => '1', fscr_scv => '1', fscr_tar => '1', fscr_dscr => '1',
|
||||
hfscr_ic => x"0", hfscr_pref => '1', hfscr_tar => '1', hfscr_dscr => '1', hfscr_fp => '1',
|
||||
dscr => (others => '0'),
|
||||
others => (others => '0'));
|
||||
|
||||
type Fetch1ToIcacheType is record
|
||||
req: std_ulogic;
|
||||
@@ -270,6 +320,7 @@ package common is
|
||||
type Decode1ToDecode2Type is record
|
||||
valid: std_ulogic;
|
||||
stop_mark : std_ulogic;
|
||||
second : std_ulogic;
|
||||
nia: std_ulogic_vector(63 downto 0);
|
||||
prefixed: std_ulogic;
|
||||
prefix: std_ulogic_vector(25 downto 0);
|
||||
@@ -286,7 +337,7 @@ package common is
|
||||
reg_c : gspr_index_t;
|
||||
end record;
|
||||
constant Decode1ToDecode2Init : Decode1ToDecode2Type :=
|
||||
(valid => '0', stop_mark => '0', nia => (others => '0'),
|
||||
(valid => '0', stop_mark => '0', second => '0', nia => (others => '0'),
|
||||
prefixed => '0', prefix => (others => '0'), insn => (others => '0'),
|
||||
illegal_suffix => '0', misaligned_prefix => '0',
|
||||
decode => decode_rom_init, br_pred => '0', big_endian => '0',
|
||||
@@ -371,11 +422,16 @@ package common is
|
||||
ramspr_wraddr : ramspr_index;
|
||||
ramspr_write_even : std_ulogic;
|
||||
ramspr_write_odd : std_ulogic;
|
||||
ramspr_32bit : std_ulogic;
|
||||
dbg_spr_access : std_ulogic;
|
||||
dec_ctr : std_ulogic;
|
||||
prefixed : std_ulogic;
|
||||
prefix : std_ulogic_vector(25 downto 0);
|
||||
illegal_suffix : std_ulogic;
|
||||
misaligned_prefix : std_ulogic;
|
||||
illegal_form : std_ulogic;
|
||||
uses_tar : std_ulogic;
|
||||
uses_dscr : std_ulogic;
|
||||
end record;
|
||||
constant Decode2ToExecute1Init : Decode2ToExecute1Type :=
|
||||
(valid => '0', unit => ALU, fac => NONE, insn_type => OP_ILLEGAL, instr_tag => instr_tag_init,
|
||||
@@ -393,9 +449,11 @@ package common is
|
||||
spr_is_ram => '0',
|
||||
ramspr_even_rdaddr => (others => '0'), ramspr_odd_rdaddr => (others => '0'), ramspr_rd_odd => '0',
|
||||
ramspr_wraddr => (others => '0'), ramspr_write_even => '0', ramspr_write_odd => '0',
|
||||
ramspr_32bit => '0',
|
||||
dbg_spr_access => '0',
|
||||
dec_ctr => '0',
|
||||
prefixed => '0', illegal_suffix => '0', misaligned_prefix => '0',
|
||||
prefixed => '0', prefix => (others => '0'), illegal_suffix => '0',
|
||||
misaligned_prefix => '0', illegal_form => '0', uses_tar => '0', uses_dscr => '0',
|
||||
others => (others => '0'));
|
||||
|
||||
type MultiplyInputType is record
|
||||
@@ -547,14 +605,23 @@ package common is
|
||||
hold : std_ulogic;
|
||||
load : std_ulogic; -- is this a load
|
||||
dcbz : std_ulogic;
|
||||
flush : std_ulogic;
|
||||
touch : std_ulogic;
|
||||
sync : std_ulogic;
|
||||
nc : std_ulogic;
|
||||
reserve : std_ulogic;
|
||||
atomic_qw : std_ulogic; -- part of a quadword atomic op
|
||||
atomic_first : std_ulogic;
|
||||
atomic_last : std_ulogic;
|
||||
virt_mode : std_ulogic;
|
||||
priv_mode : std_ulogic;
|
||||
addr : std_ulogic_vector(63 downto 0);
|
||||
data : std_ulogic_vector(63 downto 0); -- valid the cycle after .valid = 1
|
||||
byte_sel : std_ulogic_vector(7 downto 0);
|
||||
end record;
|
||||
constant Loadstore1ToDcacheInit : Loadstore1ToDcacheType :=
|
||||
(addr => (others => '0'), data => (others => '0'), byte_sel => x"00",
|
||||
others => '0');
|
||||
|
||||
type DcacheToLoadstore1Type is record
|
||||
valid : std_ulogic;
|
||||
@@ -562,6 +629,7 @@ package common is
|
||||
store_done : std_ulogic;
|
||||
error : std_ulogic;
|
||||
cache_paradox : std_ulogic;
|
||||
reserve_nc : std_ulogic;
|
||||
end record;
|
||||
|
||||
type DcacheEventType is record
|
||||
@@ -662,6 +730,8 @@ package common is
|
||||
write_xerc_enable : std_ulogic;
|
||||
xerc : xer_common_t;
|
||||
interrupt : std_ulogic;
|
||||
hv_intr : std_ulogic;
|
||||
is_scv : std_ulogic;
|
||||
intr_vec : intr_vector_t;
|
||||
redirect: std_ulogic;
|
||||
redir_mode: std_ulogic_vector(3 downto 0);
|
||||
@@ -678,7 +748,8 @@ package common is
|
||||
write_xerc_enable => '0', xerc => xerc_init,
|
||||
write_data => (others => '0'), write_cr_mask => (others => '0'),
|
||||
write_cr_data => (others => '0'), write_reg => (others => '0'),
|
||||
interrupt => '0', intr_vec => 0, redirect => '0', redir_mode => "0000",
|
||||
interrupt => '0', hv_intr => '0', is_scv => '0', intr_vec => 0,
|
||||
redirect => '0', redir_mode => "0000",
|
||||
last_nia => (others => '0'),
|
||||
br_last => '0', br_taken => '0', abs_br => '0',
|
||||
srr1 => (others => '0'), msr => (others => '0'));
|
||||
@@ -766,13 +837,13 @@ package common is
|
||||
br_last : std_ulogic;
|
||||
br_taken : std_ulogic;
|
||||
interrupt : std_ulogic;
|
||||
intr_vec : std_ulogic_vector(11 downto 0);
|
||||
intr_vec : std_ulogic_vector(16 downto 0);
|
||||
end record;
|
||||
constant WritebackToFetch1Init : WritebackToFetch1Type :=
|
||||
(redirect => '0', virt_mode => '0', priv_mode => '0', big_endian => '0',
|
||||
mode_32bit => '0', redirect_nia => (others => '0'),
|
||||
br_last => '0', br_taken => '0', br_nia => (others => '0'),
|
||||
interrupt => '0', intr_vec => x"000");
|
||||
interrupt => '0', intr_vec => 17x"0");
|
||||
|
||||
type WritebackToRegisterFileType is record
|
||||
write_reg : gspr_index_t;
|
||||
@@ -795,8 +866,10 @@ package common is
|
||||
write_cr_data => (others => '0'));
|
||||
|
||||
type WritebackToExecute1Type is record
|
||||
intr : std_ulogic;
|
||||
srr1 : std_ulogic_vector(15 downto 0);
|
||||
intr : std_ulogic;
|
||||
hv_intr : std_ulogic;
|
||||
scv_int : std_ulogic;
|
||||
srr1 : std_ulogic_vector(15 downto 0);
|
||||
end record;
|
||||
|
||||
type WritebackEventType is record
|
||||
|
||||
@@ -9,6 +9,7 @@ use work.wishbone_types.all;
|
||||
entity core is
|
||||
generic (
|
||||
SIM : boolean := false;
|
||||
CPU_INDEX : natural := 0;
|
||||
DISABLE_FLATTEN : boolean := false;
|
||||
EX1_BYPASS : boolean := true;
|
||||
HAS_FPU : boolean := true;
|
||||
@@ -48,6 +49,7 @@ entity core is
|
||||
|
||||
ext_irq : in std_ulogic;
|
||||
|
||||
run_out : out std_ulogic;
|
||||
terminated_out : out std_logic
|
||||
);
|
||||
end core;
|
||||
@@ -363,6 +365,7 @@ begin
|
||||
execute1_0: entity work.execute1
|
||||
generic map (
|
||||
SIM => SIM,
|
||||
CPU_INDEX => CPU_INDEX,
|
||||
EX1_BYPASS => EX1_BYPASS,
|
||||
HAS_FPU => HAS_FPU,
|
||||
LOG_LENGTH => LOG_LENGTH
|
||||
@@ -390,6 +393,7 @@ begin
|
||||
ls_events => loadstore_events,
|
||||
dc_events => dcache_events,
|
||||
ic_events => icache_events,
|
||||
run_out => run_out,
|
||||
terminate_out => terminate,
|
||||
dbg_spr_req => dbg_spr_req,
|
||||
dbg_spr_ack => dbg_spr_ack,
|
||||
|
||||
@@ -294,7 +294,7 @@ begin
|
||||
|
||||
-- For SPRs, use the same mapping as when the fast SPRs were in the GPR file
|
||||
valid := '1';
|
||||
sel := "000";
|
||||
sel := "0000";
|
||||
isram := '1';
|
||||
raddr := (others => '0');
|
||||
odd := '0';
|
||||
@@ -324,10 +324,26 @@ begin
|
||||
sel := SPRSEL_XER;
|
||||
when 5x"0d" =>
|
||||
raddr := RAMSPR_TAR;
|
||||
when 5x"0e" =>
|
||||
isram := '0';
|
||||
sel := SPRSEL_FSCR;
|
||||
when 5x"0f" =>
|
||||
isram := '0';
|
||||
sel := SPRSEL_HFSCR;
|
||||
when 5x"10" =>
|
||||
isram := '0';
|
||||
sel := SPRSEL_HEIR;
|
||||
when 5x"11" =>
|
||||
isram := '0';
|
||||
sel := SPRSEL_CFAR;
|
||||
when others =>
|
||||
valid := '0';
|
||||
end case;
|
||||
dbg_spr_addr <= isram & sel & std_ulogic_vector(raddr) & odd;
|
||||
if isram = '1' then
|
||||
dbg_spr_addr <= "1000" & std_ulogic_vector(raddr) & odd;
|
||||
else
|
||||
dbg_spr_addr <= "0000" & sel;
|
||||
end if;
|
||||
spr_index_valid <= valid;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
564
dcache.vhdl
564
dcache.vhdl
@@ -181,22 +181,13 @@ architecture rtl of dcache is
|
||||
|
||||
constant real_mode_perm_attr : perm_attr_t := (nocache => '0', others => '1');
|
||||
|
||||
-- Type of operation on a "valid" input
|
||||
type op_t is (OP_NONE,
|
||||
OP_BAD, -- NC cache hit, TLB miss, prot/RC failure
|
||||
OP_STCX_FAIL, -- conditional store w/o reservation
|
||||
OP_LOAD_HIT, -- Cache hit on load
|
||||
OP_LOAD_MISS, -- Load missing cache
|
||||
OP_LOAD_NC, -- Non-cachable load
|
||||
OP_STORE_HIT, -- Store hitting cache
|
||||
OP_STORE_MISS); -- Store missing cache
|
||||
|
||||
-- Cache state machine
|
||||
type state_t is (IDLE, -- Normal load hit processing
|
||||
RELOAD_WAIT_ACK, -- Cache reload wait ack
|
||||
STORE_WAIT_ACK, -- Store wait ack
|
||||
NC_LOAD_WAIT_ACK);-- Non-cachable load wait ack
|
||||
|
||||
NC_LOAD_WAIT_ACK, -- Non-cachable load wait ack
|
||||
DO_STCX, -- Check for stcx. validity
|
||||
FLUSH_CYCLE); -- Cycle for invalidating cache line
|
||||
|
||||
--
|
||||
-- Dcache operations:
|
||||
@@ -230,8 +221,9 @@ architecture rtl of dcache is
|
||||
-- Clock edge between cycle 1 and cycle 2:
|
||||
-- Request is stored in r1 (assuming r1.full was 0)
|
||||
-- The state machine transitions out of IDLE state for a load miss,
|
||||
-- a store, a dcbz, or a non-cacheable load. r1.full is set to 1
|
||||
-- for a load miss, dcbz or non-cacheable load but not a store.
|
||||
-- a store, a dcbz, a flush (dcbf) or a non-cacheable load.
|
||||
-- r1.full is set to 1 for a load miss, dcbz, flush or
|
||||
-- non-cacheable load but not a store.
|
||||
--
|
||||
-- Cycle 2: Completion signals are asserted for a load hit,
|
||||
-- a store (excluding dcbz), a TLB operation, a conditional
|
||||
@@ -272,6 +264,23 @@ architecture rtl of dcache is
|
||||
-- subsequent load requests to the same line can be completed as
|
||||
-- soon as the necessary data comes in from memory, without
|
||||
-- waiting for the whole line to be read.
|
||||
--
|
||||
-- Aligned loads and stores of a doubleword or less are atomic
|
||||
-- because they are done in a single wishbone operation.
|
||||
-- For quadword atomic loads and stores we rely on the wishbone
|
||||
-- arbiter not interrupting access to a target once it has first
|
||||
-- given access; i.e. once we have the main wishbone, no other
|
||||
-- master gets access until we drop cyc.
|
||||
--
|
||||
-- Note on loads potentially hitting the victim line that is
|
||||
-- currently being replaced: the new tag is available starting
|
||||
-- with the 3rd cycle of RELOAD_WAIT_ACK state. As long as the
|
||||
-- first read on the wishbone takes at least one cycle (i.e. the
|
||||
-- ack doesn't arrive in the same cycle as stb was asserted),
|
||||
-- r1.full will be true at least until that 3rd cycle and so a load
|
||||
-- following a load miss can't hit on the old tag of the victim
|
||||
-- line. As long as ack is not generated combinationally from
|
||||
-- stb, this will be fine.
|
||||
|
||||
-- Stage 0 register, basically contains just the latched request
|
||||
type reg_stage_0_t is record
|
||||
@@ -287,12 +296,23 @@ architecture rtl of dcache is
|
||||
signal r0_full : std_ulogic;
|
||||
|
||||
type mem_access_request_t is record
|
||||
op : op_t;
|
||||
op_lmiss : std_ulogic;
|
||||
op_store : std_ulogic;
|
||||
op_flush : std_ulogic;
|
||||
op_sync : std_ulogic;
|
||||
nc : std_ulogic;
|
||||
valid : std_ulogic;
|
||||
dcbz : std_ulogic;
|
||||
flush : std_ulogic;
|
||||
touch : std_ulogic;
|
||||
sync : std_ulogic;
|
||||
reserve : std_ulogic;
|
||||
first_dw : std_ulogic;
|
||||
last_dw : std_ulogic;
|
||||
real_addr : real_addr_t;
|
||||
data : std_ulogic_vector(63 downto 0);
|
||||
byte_sel : std_ulogic_vector(7 downto 0);
|
||||
is_hit : std_ulogic;
|
||||
hit_way : way_t;
|
||||
same_tag : std_ulogic;
|
||||
mmu_req : std_ulogic;
|
||||
@@ -306,12 +326,16 @@ architecture rtl of dcache is
|
||||
full : std_ulogic; -- have uncompleted request
|
||||
mmu_req : std_ulogic; -- request is from MMU
|
||||
req : mem_access_request_t;
|
||||
atomic_more : std_ulogic; -- atomic request isn't finished
|
||||
|
||||
-- Cache hit state
|
||||
hit_way : way_t;
|
||||
hit_load_valid : std_ulogic;
|
||||
hit_index : index_t;
|
||||
cache_hit : std_ulogic;
|
||||
prev_hit : std_ulogic;
|
||||
prev_way : way_t;
|
||||
prev_hit_reload : std_ulogic;
|
||||
|
||||
-- TLB hit state
|
||||
tlb_hit : std_ulogic;
|
||||
@@ -352,6 +376,7 @@ architecture rtl of dcache is
|
||||
mmu_done : std_ulogic;
|
||||
mmu_error : std_ulogic;
|
||||
cache_paradox : std_ulogic;
|
||||
reserve_nc : std_ulogic;
|
||||
|
||||
-- Signal to complete a failed stcx.
|
||||
stcx_fail : std_ulogic;
|
||||
@@ -365,27 +390,34 @@ architecture rtl of dcache is
|
||||
--
|
||||
type reservation_t is record
|
||||
valid : std_ulogic;
|
||||
addr : std_ulogic_vector(63 downto LINE_OFF_BITS);
|
||||
addr : std_ulogic_vector(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS);
|
||||
end record;
|
||||
|
||||
signal reservation : reservation_t;
|
||||
signal kill_rsrv : std_ulogic;
|
||||
signal kill_rsrv2 : std_ulogic;
|
||||
|
||||
-- Async signals on incoming request
|
||||
signal req_index : index_t;
|
||||
signal req_hit_way : way_t;
|
||||
signal req_tag : cache_tag_t;
|
||||
signal req_op : op_t;
|
||||
signal req_data : std_ulogic_vector(63 downto 0);
|
||||
signal req_same_tag : std_ulogic;
|
||||
signal req_go : std_ulogic;
|
||||
signal req_index : index_t;
|
||||
signal req_hit_way : way_t;
|
||||
signal req_is_hit : std_ulogic;
|
||||
signal req_tag : cache_tag_t;
|
||||
signal req_op_load_hit : std_ulogic;
|
||||
signal req_op_load_miss : std_ulogic;
|
||||
signal req_op_store : std_ulogic;
|
||||
signal req_op_flush : std_ulogic;
|
||||
signal req_op_sync : std_ulogic;
|
||||
signal req_op_bad : std_ulogic;
|
||||
signal req_op_nop : std_ulogic;
|
||||
signal req_data : std_ulogic_vector(63 downto 0);
|
||||
signal req_same_tag : std_ulogic;
|
||||
signal req_go : std_ulogic;
|
||||
signal req_nc : std_ulogic;
|
||||
signal req_hit_reload : std_ulogic;
|
||||
|
||||
signal early_req_row : row_t;
|
||||
signal early_rd_valid : std_ulogic;
|
||||
|
||||
signal cancel_store : std_ulogic;
|
||||
signal set_rsrv : std_ulogic;
|
||||
signal clear_rsrv : std_ulogic;
|
||||
|
||||
signal r0_valid : std_ulogic;
|
||||
signal r0_stall : std_ulogic;
|
||||
|
||||
@@ -427,10 +459,13 @@ architecture rtl of dcache is
|
||||
-- TLB PLRU output interface
|
||||
signal tlb_plru_victim : std_ulogic_vector(TLB_WAY_BITS-1 downto 0);
|
||||
|
||||
signal snoop_active : std_ulogic;
|
||||
signal snoop_tag_set : cache_tags_set_t;
|
||||
signal snoop_valid : std_ulogic;
|
||||
signal snoop_wrtag : cache_tag_t;
|
||||
signal snoop_index : index_t;
|
||||
signal snoop_paddr : real_addr_t;
|
||||
signal snoop_addr : real_addr_t;
|
||||
signal snoop_hits : cache_way_valids_t;
|
||||
signal req_snoop_hit : std_ulogic;
|
||||
|
||||
--
|
||||
-- Helper functions to decode incoming requests
|
||||
@@ -565,12 +600,9 @@ begin
|
||||
assert (d_in.valid and m_in.valid) = '0' report
|
||||
"request collision loadstore vs MMU";
|
||||
if m_in.valid = '1' then
|
||||
r.req := Loadstore1ToDcacheInit;
|
||||
r.req.valid := '1';
|
||||
r.req.load := not (m_in.tlbie or m_in.tlbld);
|
||||
r.req.dcbz := '0';
|
||||
r.req.nc := '0';
|
||||
r.req.reserve := '0';
|
||||
r.req.virt_mode := '0';
|
||||
r.req.priv_mode := '1';
|
||||
r.req.addr := m_in.addr;
|
||||
r.req.data := m_in.pte;
|
||||
@@ -861,34 +893,51 @@ begin
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Snoop logic
|
||||
-- Don't snoop our own cycles
|
||||
snoop_addr <= addr_to_real(wb_to_addr(snoop_in.adr));
|
||||
snoop_active <= snoop_in.cyc and snoop_in.stb and snoop_in.we and
|
||||
not (r1.wb.cyc and not wishbone_in.stall);
|
||||
kill_rsrv <= '1' when (snoop_active = '1' and reservation.valid = '1' and
|
||||
snoop_addr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) = reservation.addr)
|
||||
else '0';
|
||||
|
||||
-- Cache tag RAM second read port, for snooping
|
||||
cache_tag_read_2 : process(clk)
|
||||
variable addr : real_addr_t;
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
-- Don't snoop our own cycles
|
||||
snoop_valid <= '0';
|
||||
if not (r1.wb.cyc = '1' and wishbone_in.stall = '0') then
|
||||
if (snoop_in.cyc and snoop_in.stb and snoop_in.we) = '1' then
|
||||
snoop_valid <= '1';
|
||||
addr := addr_to_real(wb_to_addr(snoop_in.adr));
|
||||
assert not is_X(addr);
|
||||
snoop_tag_set <= cache_tags(to_integer(get_index(addr)));
|
||||
snoop_wrtag <= get_tag(addr);
|
||||
snoop_index <= get_index(addr);
|
||||
end if;
|
||||
if is_X(snoop_addr) then
|
||||
snoop_tag_set <= (others => 'X');
|
||||
else
|
||||
snoop_tag_set <= cache_tags(to_integer(get_index(snoop_addr)));
|
||||
end if;
|
||||
snoop_paddr <= snoop_addr;
|
||||
snoop_valid <= snoop_active;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Compare the previous cycle's snooped store address to the reservation,
|
||||
-- to catch the case where a write happens on cycle 1 of a cached larx
|
||||
kill_rsrv2 <= '1' when (snoop_valid = '1' and reservation.valid = '1' and
|
||||
snoop_paddr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) = reservation.addr)
|
||||
else '0';
|
||||
|
||||
snoop_tag_match : process(all)
|
||||
begin
|
||||
snoop_hits <= (others => '0');
|
||||
for i in 0 to NUM_WAYS-1 loop
|
||||
if snoop_valid = '1' and read_tag(i, snoop_tag_set) = get_tag(snoop_paddr) then
|
||||
snoop_hits(i) <= '1';
|
||||
end if;
|
||||
end loop;
|
||||
end process;
|
||||
|
||||
-- Cache request parsing and hit detection
|
||||
dcache_request : process(all)
|
||||
variable req_row : row_t;
|
||||
variable rindex : index_t;
|
||||
variable is_hit : std_ulogic;
|
||||
variable hit_way : way_t;
|
||||
variable op : op_t;
|
||||
variable opsel : std_ulogic_vector(2 downto 0);
|
||||
variable go : std_ulogic;
|
||||
variable nc : std_ulogic;
|
||||
variable s_hit : std_ulogic;
|
||||
@@ -901,6 +950,9 @@ begin
|
||||
variable rel_match : std_ulogic;
|
||||
variable fwd_matches : std_ulogic_vector(TLB_NUM_WAYS - 1 downto 0);
|
||||
variable fwd_match : std_ulogic;
|
||||
variable snp_matches : std_ulogic_vector(TLB_NUM_WAYS - 1 downto 0);
|
||||
variable snoop_match : std_ulogic;
|
||||
variable hit_reload : std_ulogic;
|
||||
begin
|
||||
-- Extract line, row and tag from request
|
||||
rindex := get_index(r0.req.addr);
|
||||
@@ -924,9 +976,11 @@ begin
|
||||
is_hit := '0';
|
||||
rel_match := '0';
|
||||
fwd_match := '0';
|
||||
snoop_match := '0';
|
||||
if r0.req.virt_mode = '1' then
|
||||
rel_matches := (others => '0');
|
||||
fwd_matches := (others => '0');
|
||||
snp_matches := (others => '0');
|
||||
for j in tlb_way_t loop
|
||||
hit_way_set(j) := to_unsigned(0, WAY_BITS);
|
||||
s_hit := '0';
|
||||
@@ -943,6 +997,9 @@ begin
|
||||
tlb_valid_way(j) = '1' then
|
||||
hit_way_set(j) := to_unsigned(i, WAY_BITS);
|
||||
s_hit := '1';
|
||||
if snoop_hits(i) = '1' then
|
||||
snp_matches(j) := '1';
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
hit_set(j) := s_hit;
|
||||
@@ -959,6 +1016,7 @@ begin
|
||||
hit_way := hit_way_set(to_integer(tlb_hit_way));
|
||||
rel_match := rel_matches(to_integer(tlb_hit_way));
|
||||
fwd_match := fwd_matches(to_integer(tlb_hit_way));
|
||||
snoop_match := snp_matches(to_integer(tlb_hit_way));
|
||||
end if;
|
||||
else
|
||||
s_tag := get_tag(r0.req.addr);
|
||||
@@ -970,6 +1028,9 @@ begin
|
||||
read_tag(i, cache_tag_set) = s_tag then
|
||||
hit_way := to_unsigned(i, WAY_BITS);
|
||||
is_hit := '1';
|
||||
if snoop_hits(i) = '1' then
|
||||
snoop_match := '1';
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
if go = '1' and not is_X(r1.reload_tag) and s_tag = r1.reload_tag then
|
||||
@@ -982,6 +1043,13 @@ begin
|
||||
req_same_tag <= rel_match;
|
||||
fwd_same_tag <= fwd_match;
|
||||
|
||||
-- This is 1 if the snooped write from the previous cycle hits the same
|
||||
-- cache line that is being accessed in this cycle.
|
||||
req_snoop_hit <= '0';
|
||||
if go = '1' and snoop_match = '1' and get_index(snoop_paddr) = rindex then
|
||||
req_snoop_hit <= '1';
|
||||
end if;
|
||||
|
||||
-- Whether to use forwarded data for a load or not
|
||||
use_forward_st <= '0';
|
||||
use_forward_rl <= '0';
|
||||
@@ -1029,6 +1097,7 @@ begin
|
||||
assert not is_X(rindex);
|
||||
assert not is_X(r1.store_index);
|
||||
end if;
|
||||
hit_reload := '0';
|
||||
if r1.state = RELOAD_WAIT_ACK and rel_match = '1' and
|
||||
rindex = r1.store_index then
|
||||
-- Ignore is_hit from above, because a load miss writes the new tag
|
||||
@@ -1037,13 +1106,29 @@ begin
|
||||
-- since it will be by the time we perform the store.
|
||||
-- For a load, check the appropriate row valid bit; but also,
|
||||
-- if use_forward_rl is 1 then we can consider this a hit.
|
||||
is_hit := not r0.req.load or r1.rows_valid(to_integer(req_row(ROW_LINEBITS-1 downto 0))) or
|
||||
-- For a touch, since the line we want is being reloaded already,
|
||||
-- consider this a hit.
|
||||
is_hit := not r0.req.load or r0.req.touch or
|
||||
r1.rows_valid(to_integer(req_row(ROW_LINEBITS-1 downto 0))) or
|
||||
use_forward_rl;
|
||||
hit_way := replace_way;
|
||||
hit_reload := is_hit;
|
||||
elsif r0.req.load = '1' and r0.req.atomic_qw = '1' and r0.req.atomic_first = '0' and
|
||||
r0.req.nc = '0' and perm_attr.nocache = '0' and r1.prev_hit = '1' then
|
||||
-- For the second half of an atomic quadword load, just use the
|
||||
-- same way as the first half, without considering whether the line
|
||||
-- is valid; it is as if we had read the second dword at the same
|
||||
-- time as the first dword, and the line was valid back then.
|
||||
-- (Cases where the line is currently being reloaded are handled above.)
|
||||
-- NB lq to noncacheable isn't required to be atomic per the ISA.
|
||||
is_hit := '1';
|
||||
hit_way := r1.prev_way;
|
||||
end if;
|
||||
|
||||
-- The way that matched on a hit
|
||||
req_hit_way <= hit_way;
|
||||
req_is_hit <= is_hit;
|
||||
req_hit_reload <= hit_reload;
|
||||
|
||||
-- work out whether we have permission for this access
|
||||
-- NB we don't yet implement AMR, thus no KUAP
|
||||
@@ -1056,29 +1141,44 @@ begin
|
||||
-- operation needs to be done
|
||||
--
|
||||
nc := r0.req.nc or perm_attr.nocache;
|
||||
op := OP_NONE;
|
||||
req_op_bad <= '0';
|
||||
req_op_load_hit <= '0';
|
||||
req_op_load_miss <= '0';
|
||||
req_op_store <= '0';
|
||||
req_op_nop <= '0';
|
||||
req_op_flush <= '0';
|
||||
req_op_sync <= '0';
|
||||
if go = '1' then
|
||||
if access_ok = '0' then
|
||||
op := OP_BAD;
|
||||
elsif cancel_store = '1' then
|
||||
op := OP_STCX_FAIL;
|
||||
if r0.req.sync = '1' then
|
||||
req_op_sync <= '1';
|
||||
elsif r0.req.touch = '1' then
|
||||
if access_ok = '1' and is_hit = '0' and nc = '0' then
|
||||
req_op_load_miss <= '1';
|
||||
elsif access_ok = '1' and is_hit = '1' and nc = '0' then
|
||||
-- Make this OP_LOAD_HIT so the PLRU gets updated
|
||||
req_op_load_hit <= '1';
|
||||
else
|
||||
req_op_nop <= '1';
|
||||
end if;
|
||||
elsif access_ok = '0' then
|
||||
req_op_bad <= '1';
|
||||
elsif r0.req.flush = '1' then
|
||||
if is_hit = '0' then
|
||||
req_op_nop <= '1';
|
||||
else
|
||||
req_op_flush <= '1';
|
||||
end if;
|
||||
elsif nc = '1' and (is_hit = '1' or r0.req.reserve = '1') then
|
||||
req_op_bad <= '1';
|
||||
elsif r0.req.load = '0' then
|
||||
req_op_store <= '1'; -- includes dcbz
|
||||
else
|
||||
opsel := r0.req.load & nc & is_hit;
|
||||
case opsel is
|
||||
when "101" => op := OP_LOAD_HIT;
|
||||
when "100" => op := OP_LOAD_MISS;
|
||||
when "110" => op := OP_LOAD_NC;
|
||||
when "001" => op := OP_STORE_HIT;
|
||||
when "000" => op := OP_STORE_MISS;
|
||||
when "010" => op := OP_STORE_MISS;
|
||||
when "011" => op := OP_BAD;
|
||||
when "111" => op := OP_BAD;
|
||||
when others => op := OP_NONE;
|
||||
end case;
|
||||
req_op_load_hit <= is_hit;
|
||||
req_op_load_miss <= not is_hit; -- includes non-cacheable loads
|
||||
end if;
|
||||
end if;
|
||||
req_op <= op;
|
||||
req_go <= go;
|
||||
req_nc <= nc;
|
||||
|
||||
-- Version of the row number that is valid one cycle earlier
|
||||
-- in the cases where we need to read the cache data BRAM.
|
||||
@@ -1101,45 +1201,6 @@ begin
|
||||
-- Wire up wishbone request latch out of stage 1
|
||||
wishbone_out <= r1.wb;
|
||||
|
||||
-- Handle load-with-reservation and store-conditional instructions
|
||||
reservation_comb: process(all)
|
||||
begin
|
||||
cancel_store <= '0';
|
||||
set_rsrv <= '0';
|
||||
clear_rsrv <= '0';
|
||||
if r0_valid = '1' and r0.req.reserve = '1' then
|
||||
-- XXX generate alignment interrupt if address is not aligned
|
||||
-- XXX or if r0.req.nc = '1'
|
||||
if r0.req.load = '1' then
|
||||
-- load with reservation
|
||||
set_rsrv <= '1';
|
||||
else
|
||||
-- store conditional
|
||||
clear_rsrv <= '1';
|
||||
if reservation.valid = '0' or
|
||||
r0.req.addr(63 downto LINE_OFF_BITS) /= reservation.addr then
|
||||
cancel_store <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
reservation_reg: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
reservation.valid <= '0';
|
||||
elsif r0_valid = '1' and access_ok = '1' then
|
||||
if clear_rsrv = '1' then
|
||||
reservation.valid <= '0';
|
||||
elsif set_rsrv = '1' then
|
||||
reservation.valid <= '1';
|
||||
reservation.addr <= r0.req.addr(63 downto LINE_OFF_BITS);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Return data for loads & completion control logic
|
||||
--
|
||||
writeback_control: process(all)
|
||||
@@ -1149,6 +1210,7 @@ begin
|
||||
d_out.store_done <= not r1.stcx_fail;
|
||||
d_out.error <= r1.ls_error;
|
||||
d_out.cache_paradox <= r1.cache_paradox;
|
||||
d_out.reserve_nc <= r1.reserve_nc;
|
||||
|
||||
-- Outputs to MMU
|
||||
m_out.done <= r1.mmu_done;
|
||||
@@ -1185,7 +1247,7 @@ begin
|
||||
report "completing ld/st with error";
|
||||
end if;
|
||||
|
||||
-- Slow ops (load miss, NC, stores)
|
||||
-- Slow ops (load miss, NC, stores, sync)
|
||||
if r1.slow_valid = '1' then
|
||||
report "completing store or load miss data=" & to_hstring(r1.data_out);
|
||||
end if;
|
||||
@@ -1288,14 +1350,6 @@ begin
|
||||
variable data_out : std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if req_op /= OP_NONE then
|
||||
report "op:" & op_t'image(req_op) &
|
||||
" addr:" & to_hstring(r0.req.addr) &
|
||||
" nc:" & std_ulogic'image(r0.req.nc) &
|
||||
" idx:" & to_hstring(req_index) &
|
||||
" tag:" & to_hstring(req_tag) &
|
||||
" way: " & to_hstring(req_hit_way);
|
||||
end if;
|
||||
if r0_valid = '1' then
|
||||
r1.mmu_req <= r0.mmu_req;
|
||||
end if;
|
||||
@@ -1341,36 +1395,19 @@ begin
|
||||
r1.forward_valid <= '1';
|
||||
end if;
|
||||
|
||||
-- Fast path for load/store hits. Set signals for the writeback controls.
|
||||
if req_op = OP_LOAD_HIT then
|
||||
r1.hit_load_valid <= '1';
|
||||
else
|
||||
r1.hit_load_valid <= '0';
|
||||
end if;
|
||||
r1.hit_load_valid <= req_op_load_hit;
|
||||
r1.cache_hit <= req_op_load_hit or (req_op_store and req_is_hit); -- causes PLRU update
|
||||
|
||||
-- The cache hit indication is used for PLRU updates
|
||||
if req_op = OP_LOAD_HIT or req_op = OP_STORE_HIT then
|
||||
r1.cache_hit <= '1';
|
||||
else
|
||||
r1.cache_hit <= '0';
|
||||
end if;
|
||||
|
||||
if req_op = OP_BAD then
|
||||
r1.cache_paradox <= access_ok and req_nc and req_is_hit;
|
||||
r1.reserve_nc <= access_ok and r0.req.reserve and req_nc;
|
||||
if req_op_bad = '1' then
|
||||
report "Signalling ld/st error valid_ra=" & std_ulogic'image(valid_ra) &
|
||||
" rc_ok=" & std_ulogic'image(rc_ok) & " perm_ok=" & std_ulogic'image(perm_ok);
|
||||
r1.ls_error <= not r0.mmu_req;
|
||||
r1.mmu_error <= r0.mmu_req;
|
||||
r1.cache_paradox <= access_ok;
|
||||
else
|
||||
r1.ls_error <= '0';
|
||||
r1.mmu_error <= '0';
|
||||
r1.cache_paradox <= '0';
|
||||
end if;
|
||||
|
||||
if req_op = OP_STCX_FAIL then
|
||||
r1.stcx_fail <= '1';
|
||||
else
|
||||
r1.stcx_fail <= '0';
|
||||
end if;
|
||||
|
||||
-- Record TLB hit information for updating TLB PLRU
|
||||
@@ -1423,6 +1460,10 @@ begin
|
||||
r1.acks_pending <= to_unsigned(0, 3);
|
||||
r1.stalled <= '0';
|
||||
r1.dec_acks <= '0';
|
||||
r1.prev_hit <= '0';
|
||||
r1.prev_hit_reload <= '0';
|
||||
reservation.valid <= '0';
|
||||
reservation.addr <= (others => '0');
|
||||
|
||||
-- Not useful normally but helps avoiding tons of sim warnings
|
||||
r1.wb.adr <= (others => '0');
|
||||
@@ -1430,27 +1471,33 @@ begin
|
||||
-- One cycle pulses reset
|
||||
r1.slow_valid <= '0';
|
||||
r1.write_bram <= '0';
|
||||
r1.stcx_fail <= '0';
|
||||
|
||||
r1.ls_valid <= '0';
|
||||
r1.ls_valid <= (req_op_load_hit or req_op_nop) and not r0.mmu_req;
|
||||
-- complete tlbies and TLB loads in the third cycle
|
||||
r1.mmu_done <= r0_valid and (r0.tlbie or r0.tlbld);
|
||||
if req_op = OP_LOAD_HIT or req_op = OP_STCX_FAIL then
|
||||
if r0.mmu_req = '0' then
|
||||
r1.ls_valid <= '1';
|
||||
else
|
||||
r1.mmu_done <= '1';
|
||||
end if;
|
||||
r1.mmu_done <= (r0_valid and (r0.tlbie or r0.tlbld)) or
|
||||
(req_op_load_hit and r0.mmu_req);
|
||||
|
||||
-- The kill_rsrv2 term covers the case where the reservation
|
||||
-- address was set at the beginning of this cycle, and a store
|
||||
-- to that address happened in the previous cycle.
|
||||
if kill_rsrv = '1' or kill_rsrv2 = '1' then
|
||||
reservation.valid <= '0';
|
||||
end if;
|
||||
if req_go = '1' and access_ok = '1' and r0.req.load = '1' and
|
||||
r0.req.reserve = '1' and r0.req.atomic_first = '1' then
|
||||
reservation.addr <= ra(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS);
|
||||
reservation.valid <= req_is_hit and not req_snoop_hit;
|
||||
end if;
|
||||
|
||||
-- Do invalidations from snooped stores to memory
|
||||
if snoop_valid = '1' then
|
||||
assert not is_X(snoop_tag_set);
|
||||
assert not is_X(snoop_wrtag);
|
||||
assert not is_X(snoop_paddr);
|
||||
assert not is_X(snoop_hits);
|
||||
end if;
|
||||
for i in 0 to NUM_WAYS-1 loop
|
||||
if snoop_valid = '1' and read_tag(i, snoop_tag_set) = snoop_wrtag then
|
||||
assert not is_X(snoop_index);
|
||||
cache_valids(to_integer(snoop_index))(i) <= '0';
|
||||
if snoop_hits(i) = '1' then
|
||||
cache_valids(to_integer(get_index(snoop_paddr)))(i) <= '0';
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
@@ -1469,14 +1516,24 @@ begin
|
||||
end if;
|
||||
|
||||
-- Take request from r1.req if there is one there,
|
||||
-- else from req_op, ra, etc.
|
||||
-- else from req_op_*, ra, etc.
|
||||
if r1.full = '1' then
|
||||
req := r1.req;
|
||||
else
|
||||
req.op := req_op;
|
||||
req.op_lmiss := req_op_load_miss;
|
||||
req.op_store := req_op_store;
|
||||
req.op_flush := req_op_flush;
|
||||
req.op_sync := req_op_sync;
|
||||
req.nc := req_nc;
|
||||
req.valid := req_go;
|
||||
req.mmu_req := r0.mmu_req;
|
||||
req.dcbz := r0.req.dcbz;
|
||||
req.flush := r0.req.flush;
|
||||
req.touch := r0.req.touch;
|
||||
req.sync := r0.req.sync;
|
||||
req.reserve := r0.req.reserve;
|
||||
req.first_dw := not r0.req.atomic_qw or r0.req.atomic_first;
|
||||
req.last_dw := not r0.req.atomic_qw or r0.req.atomic_last;
|
||||
req.real_addr := ra;
|
||||
-- Force data to 0 for dcbz
|
||||
if r0.req.dcbz = '1' then
|
||||
@@ -1493,14 +1550,16 @@ begin
|
||||
req.byte_sel := r0.req.byte_sel;
|
||||
end if;
|
||||
req.hit_way := req_hit_way;
|
||||
req.is_hit := req_is_hit;
|
||||
req.same_tag := req_same_tag;
|
||||
|
||||
-- Store the incoming request from r0, if it is a slow request
|
||||
-- Note that r1.full = 1 implies req_op = OP_NONE
|
||||
if req_op = OP_LOAD_MISS or req_op = OP_LOAD_NC or
|
||||
req_op = OP_STORE_MISS or req_op = OP_STORE_HIT then
|
||||
-- Note that r1.full = 1 implies none of the req_op_* are 1.
|
||||
-- For the sake of timing we put any valid request in r1.req,
|
||||
-- but only set r1.full if it is a slow request.
|
||||
if req_go = '1' then
|
||||
r1.req <= req;
|
||||
r1.full <= '1';
|
||||
r1.full <= req_op_load_miss or req_op_store or req_op_flush or req_op_sync;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
@@ -1512,9 +1571,14 @@ begin
|
||||
r1.victim_way <= plru_victim;
|
||||
report "victim way:" & to_hstring(plru_victim);
|
||||
end if;
|
||||
if req_op = OP_LOAD_MISS or (req_op = OP_STORE_MISS and r0.req.dcbz = '1') then
|
||||
if req_op_load_miss = '1' or (r0.req.dcbz = '1' and req_is_hit = '0') then
|
||||
r1.choose_victim <= '1';
|
||||
end if;
|
||||
if req_go = '1' then
|
||||
r1.prev_hit <= req_is_hit;
|
||||
r1.prev_way <= req_hit_way;
|
||||
r1.prev_hit_reload <= req_hit_reload;
|
||||
end if;
|
||||
|
||||
-- Update count of pending acks
|
||||
acks := r1.acks_pending;
|
||||
@@ -1536,6 +1600,7 @@ begin
|
||||
r1.wb.sel <= req.byte_sel;
|
||||
r1.wb.dat <= req.data;
|
||||
r1.dcbz <= req.dcbz;
|
||||
r1.atomic_more <= not req.last_dw;
|
||||
|
||||
-- Keep track of our index and way for subsequent stores.
|
||||
r1.store_index <= get_index(req.real_addr);
|
||||
@@ -1544,44 +1609,52 @@ begin
|
||||
r1.reload_tag <= get_tag(req.real_addr);
|
||||
r1.req.same_tag <= '1';
|
||||
|
||||
if req.op = OP_STORE_HIT then
|
||||
if req.is_hit = '1' then
|
||||
r1.store_way <= req.hit_way;
|
||||
end if;
|
||||
|
||||
-- Reset per-row valid bits, ready for handling OP_LOAD_MISS
|
||||
-- Reset per-row valid bits, ready for handling the next load miss
|
||||
for i in 0 to ROW_PER_LINE - 1 loop
|
||||
r1.rows_valid(i) <= '0';
|
||||
end loop;
|
||||
|
||||
case req.op is
|
||||
when OP_LOAD_HIT =>
|
||||
-- stay in IDLE state
|
||||
|
||||
when OP_LOAD_MISS =>
|
||||
if req.op_lmiss = '1' then
|
||||
-- Normal load cache miss, start the reload machine
|
||||
--
|
||||
report "cache miss real addr:" & to_hstring(req.real_addr) &
|
||||
" idx:" & to_hstring(get_index(req.real_addr)) &
|
||||
" tag:" & to_hstring(get_tag(req.real_addr));
|
||||
-- Or non-cacheable load
|
||||
if req.nc = '0' then
|
||||
report "cache miss real addr:" & to_hstring(req.real_addr) &
|
||||
" idx:" & to_hstring(get_index(req.real_addr)) &
|
||||
" tag:" & to_hstring(get_tag(req.real_addr));
|
||||
end if;
|
||||
|
||||
-- Start the wishbone cycle
|
||||
r1.wb.we <= '0';
|
||||
r1.wb.cyc <= '1';
|
||||
r1.wb.stb <= '1';
|
||||
|
||||
-- Track that we had one request sent
|
||||
r1.state <= RELOAD_WAIT_ACK;
|
||||
r1.write_tag <= '1';
|
||||
ev.load_miss <= '1';
|
||||
if req.nc = '0' then
|
||||
-- Track that we had one request sent
|
||||
r1.state <= RELOAD_WAIT_ACK;
|
||||
r1.write_tag <= '1';
|
||||
ev.load_miss <= '1';
|
||||
|
||||
when OP_LOAD_NC =>
|
||||
r1.wb.cyc <= '1';
|
||||
r1.wb.stb <= '1';
|
||||
r1.wb.we <= '0';
|
||||
r1.state <= NC_LOAD_WAIT_ACK;
|
||||
-- If this is a touch, complete the instruction
|
||||
if req.touch = '1' then
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
r1.ls_valid <= '1';
|
||||
end if;
|
||||
else
|
||||
r1.state <= NC_LOAD_WAIT_ACK;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when OP_STORE_HIT | OP_STORE_MISS =>
|
||||
if req.dcbz = '0' then
|
||||
if req.op_store = '1' then
|
||||
if req.reserve = '1' then
|
||||
-- stcx needs to wait until next cycle
|
||||
-- for the reservation address check
|
||||
r1.state <= DO_STCX;
|
||||
elsif req.dcbz = '0' then
|
||||
r1.state <= STORE_WAIT_ACK;
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
@@ -1590,30 +1663,33 @@ begin
|
||||
else
|
||||
r1.mmu_done <= '1';
|
||||
end if;
|
||||
if req.op = OP_STORE_HIT then
|
||||
r1.write_bram <= '1';
|
||||
end if;
|
||||
r1.write_bram <= req.is_hit;
|
||||
r1.wb.we <= '1';
|
||||
r1.wb.cyc <= '1';
|
||||
r1.wb.stb <= '1';
|
||||
else
|
||||
-- dcbz is handled much like a load miss except
|
||||
-- that we are writing to memory instead of reading
|
||||
r1.state <= RELOAD_WAIT_ACK;
|
||||
if req.op = OP_STORE_MISS then
|
||||
r1.write_tag <= '1';
|
||||
end if;
|
||||
end if;
|
||||
r1.wb.we <= '1';
|
||||
r1.wb.cyc <= '1';
|
||||
r1.wb.stb <= '1';
|
||||
if req.op = OP_STORE_MISS then
|
||||
ev.store_miss <= '1';
|
||||
r1.write_tag <= not req.is_hit;
|
||||
r1.wb.we <= '1';
|
||||
r1.wb.cyc <= '1';
|
||||
r1.wb.stb <= '1';
|
||||
end if;
|
||||
ev.store_miss <= not req.is_hit;
|
||||
end if;
|
||||
|
||||
-- OP_NONE and OP_BAD do nothing
|
||||
-- OP_BAD & OP_STCX_FAIL were handled above already
|
||||
when OP_NONE =>
|
||||
when OP_BAD =>
|
||||
when OP_STCX_FAIL =>
|
||||
end case;
|
||||
if req.op_flush = '1' then
|
||||
r1.state <= FLUSH_CYCLE;
|
||||
end if;
|
||||
|
||||
if req.op_sync = '1' then
|
||||
-- sync/lwsync can complete now that the state machine
|
||||
-- is idle.
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
r1.ls_valid <= '1';
|
||||
end if;
|
||||
|
||||
when RELOAD_WAIT_ACK =>
|
||||
-- If we are still sending requests, was one accepted ?
|
||||
@@ -1643,7 +1719,7 @@ begin
|
||||
assert not is_X(r1.req.real_addr);
|
||||
end if;
|
||||
if r1.full = '1' and r1.req.same_tag = '1' and
|
||||
((r1.dcbz = '1' and req.dcbz = '1') or r1.req.op = OP_LOAD_MISS) and
|
||||
((r1.dcbz = '1' and r1.req.dcbz = '1') or r1.req.op_lmiss = '1') and
|
||||
r1.store_row = get_row(r1.req.real_addr) then
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
@@ -1652,6 +1728,10 @@ begin
|
||||
else
|
||||
r1.mmu_done <= '1';
|
||||
end if;
|
||||
-- NB: for lqarx, set the reservation on the first dword
|
||||
if r1.req.reserve = '1' and r1.req.first_dw = '1' then
|
||||
reservation.valid <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Check for completion
|
||||
@@ -1667,6 +1747,10 @@ begin
|
||||
cache_valids(to_integer(r1.store_index))(to_integer(r1.store_way)) <= '1';
|
||||
|
||||
ev.dcache_refill <= not r1.dcbz;
|
||||
-- Second half of a lq/lqarx can assume a hit on this line now
|
||||
-- if the first half hit this line.
|
||||
r1.prev_hit <= r1.prev_hit_reload;
|
||||
r1.prev_way <= r1.store_way;
|
||||
r1.state <= IDLE;
|
||||
end if;
|
||||
|
||||
@@ -1680,6 +1764,10 @@ begin
|
||||
if wishbone_in.stall = '0' then
|
||||
-- See if there is another store waiting to be done
|
||||
-- which is in the same real page.
|
||||
-- This could be either in r1.req or in r0.
|
||||
-- Ignore store-conditionals, they have to go through
|
||||
-- DO_STCX state, unless they are the second half of a
|
||||
-- successful stqcx, which is handled here.
|
||||
if req.valid = '1' then
|
||||
r1.wb.adr(SET_SIZE_BITS - ROW_OFF_BITS - 1 downto 0) <=
|
||||
req.real_addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS);
|
||||
@@ -1687,30 +1775,33 @@ begin
|
||||
r1.wb.sel <= req.byte_sel;
|
||||
end if;
|
||||
assert not is_X(acks);
|
||||
if acks < 7 and req.same_tag = '1' and req.dcbz = '0' and
|
||||
(req.op = OP_STORE_MISS or req.op = OP_STORE_HIT) then
|
||||
r1.wb.stb <= '1';
|
||||
stbs_done := false;
|
||||
r1.store_way <= req.hit_way;
|
||||
r1.store_row <= get_row(req.real_addr);
|
||||
if req.op = OP_STORE_HIT then
|
||||
r1.write_bram <= '1';
|
||||
r1.wb.stb <= '0';
|
||||
if req.op_store = '1' and req.same_tag = '1' and req.dcbz = '0' and
|
||||
(req.reserve = '0' or r1.atomic_more = '1') then
|
||||
if acks < 7 then
|
||||
r1.wb.stb <= '1';
|
||||
stbs_done := false;
|
||||
r1.store_way <= req.hit_way;
|
||||
r1.store_row <= get_row(req.real_addr);
|
||||
r1.write_bram <= req.is_hit;
|
||||
r1.atomic_more <= not req.last_dw;
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
-- Store requests never come from the MMU
|
||||
r1.ls_valid <= '1';
|
||||
end if;
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
-- Store requests never come from the MMU
|
||||
r1.ls_valid <= '1';
|
||||
stbs_done := false;
|
||||
else
|
||||
r1.wb.stb <= '0';
|
||||
stbs_done := true;
|
||||
if req.valid = '1' then
|
||||
r1.atomic_more <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Got ack ? See if complete.
|
||||
if wishbone_in.ack = '1' then
|
||||
if stbs_done and r1.atomic_more = '0' then
|
||||
assert not is_X(acks);
|
||||
if stbs_done and acks = 1 then
|
||||
if acks = 0 or (wishbone_in.ack = '1' and acks = 1) then
|
||||
r1.state <= IDLE;
|
||||
r1.wb.cyc <= '0';
|
||||
r1.wb.stb <= '0';
|
||||
@@ -1736,6 +1827,51 @@ begin
|
||||
r1.wb.cyc <= '0';
|
||||
r1.wb.stb <= '0';
|
||||
end if;
|
||||
|
||||
when DO_STCX =>
|
||||
if reservation.valid = '0' or kill_rsrv = '1' or
|
||||
r1.req.real_addr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) /= reservation.addr then
|
||||
-- Wrong address, didn't have reservation, or lost reservation
|
||||
-- Abandon the wishbone cycle if started and fail the stcx.
|
||||
r1.stcx_fail <= '1';
|
||||
r1.full <= '0';
|
||||
r1.ls_valid <= '1';
|
||||
r1.state <= IDLE;
|
||||
r1.wb.cyc <= '0';
|
||||
r1.wb.stb <= '0';
|
||||
reservation.valid <= '0';
|
||||
-- If this is the first half of a stqcx., the second half
|
||||
-- will fail also because the reservation is not valid.
|
||||
r1.state <= IDLE;
|
||||
elsif r1.wb.cyc = '0' then
|
||||
-- Right address and have reservation, so start the
|
||||
-- wishbone cycle
|
||||
r1.wb.we <= '1';
|
||||
r1.wb.cyc <= '1';
|
||||
r1.wb.stb <= '1';
|
||||
elsif r1.wb.stb = '1' and wishbone_in.stall = '0' then
|
||||
-- Store has been accepted, so now we can write the
|
||||
-- cache data RAM and complete the request
|
||||
r1.write_bram <= r1.req.is_hit;
|
||||
r1.wb.stb <= '0';
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
r1.ls_valid <= '1';
|
||||
reservation.valid <= '0';
|
||||
-- For a stqcx, STORE_WAIT_ACK will issue the second half
|
||||
-- without checking the reservation, which is what we want
|
||||
-- given that the first half has gone out.
|
||||
-- With r1.atomic_more set, STORE_WAIT_ACK won't exit to
|
||||
-- IDLE state until it sees the second half.
|
||||
r1.state <= STORE_WAIT_ACK;
|
||||
end if;
|
||||
|
||||
when FLUSH_CYCLE =>
|
||||
cache_valids(to_integer(r1.store_index))(to_integer(r1.store_way)) <= '0';
|
||||
r1.full <= '0';
|
||||
r1.slow_valid <= '1';
|
||||
r1.ls_valid <= '1';
|
||||
r1.state <= IDLE;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
@@ -1753,7 +1889,7 @@ begin
|
||||
r1.wb.stb & r1.wb.cyc &
|
||||
d_out.error &
|
||||
d_out.valid &
|
||||
std_ulogic_vector(to_unsigned(op_t'pos(req_op), 3)) &
|
||||
req_op_load_miss & req_op_store & req_op_bad &
|
||||
stall_out &
|
||||
std_ulogic_vector(resize(tlb_hit_way, 3)) &
|
||||
valid_ra &
|
||||
|
||||
157
decode1.vhdl
157
decode1.vhdl
@@ -44,6 +44,8 @@ architecture behaviour of decode1 is
|
||||
signal decode_rom_addr : insn_code;
|
||||
signal decode : decode_rom_t;
|
||||
|
||||
signal double : std_ulogic;
|
||||
|
||||
type prefix_state_t is record
|
||||
prefixed : std_ulogic;
|
||||
prefix : std_ulogic_vector(25 downto 0);
|
||||
@@ -106,6 +108,7 @@ architecture behaviour of decode1 is
|
||||
INSN_brd => (ALU, NONE, OP_BREV, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cbcdtd => (ALU, NONE, OP_BCD, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cdtbcd => (ALU, NONE, OP_BCD, NONE, NONE, RS, RA, '0', '0', '1', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cfuged => (ALU, NONE, OP_BSORT, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cmp => (ALU, NONE, OP_CMP, RA, RB, NONE, NONE, '0', '1', '1', '0', ONE, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE),
|
||||
INSN_cmpb => (ALU, NONE, OP_CMPB, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cmpeqb => (ALU, NONE, OP_CMPEQB, RA, RB, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
@@ -113,10 +116,10 @@ architecture behaviour of decode1 is
|
||||
INSN_cmpl => (ALU, NONE, OP_CMP, RA, RB, NONE, NONE, '0', '1', '1', '0', ONE, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cmpli => (ALU, NONE, OP_CMP, RA, CONST_UI, NONE, NONE, '0', '1', '1', '0', ONE, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cmprb => (ALU, NONE, OP_CMPRB, RA, RB, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_cntlzd => (ALU, NONE, OP_CNTZ, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
INSN_cntlzw => (ALU, NONE, OP_CNTZ, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE),
|
||||
INSN_cnttzd => (ALU, NONE, OP_CNTZ, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
INSN_cnttzw => (ALU, NONE, OP_CNTZ, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE),
|
||||
INSN_cntlzd => (ALU, NONE, OP_COUNTB, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
INSN_cntlzw => (ALU, NONE, OP_COUNTB, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE),
|
||||
INSN_cnttzd => (ALU, NONE, OP_COUNTB, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
INSN_cnttzw => (ALU, NONE, OP_COUNTB, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE),
|
||||
INSN_crand => (ALU, NONE, OP_CROP, NONE, NONE, NONE, NONE, '1', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_crandc => (ALU, NONE, OP_CROP, NONE, NONE, NONE, NONE, '1', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_creqv => (ALU, NONE, OP_CROP, NONE, NONE, NONE, NONE, '1', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
@@ -126,10 +129,10 @@ architecture behaviour of decode1 is
|
||||
INSN_crorc => (ALU, NONE, OP_CROP, NONE, NONE, NONE, NONE, '1', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_crxor => (ALU, NONE, OP_CROP, NONE, NONE, NONE, NONE, '1', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_darn => (ALU, NONE, OP_DARN, NONE, NONE, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbf => (ALU, NONE, OP_DCBF, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbf => (LDST, NONE, OP_DCBF, RA_OR_ZERO, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbst => (ALU, NONE, OP_DCBST, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbt => (ALU, NONE, OP_DCBT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbtst => (ALU, NONE, OP_DCBTST, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbt => (LDST, NONE, OP_LOAD, RA_OR_ZERO, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbtst => (LDST, NONE, OP_STORE, RA_OR_ZERO, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_dcbz => (LDST, NONE, OP_DCBZ, RA_OR_ZERO, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_divd => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RCOE, '0', '0', NONE),
|
||||
INSN_divde => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RCOE, '0', '0', NONE),
|
||||
@@ -197,7 +200,7 @@ architecture behaviour of decode1 is
|
||||
INSN_ftdiv => (FPU, FPU, OP_FP_CMP, FRA, FRB, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_ftsqrt => (FPU, FPU, OP_FP_CMP, NONE, FRB, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_icbi => (ALU, NONE, OP_ICBI, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE),
|
||||
INSN_icbt => (ALU, NONE, OP_ICBT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE),
|
||||
INSN_icbt => (ALU, NONE, OP_ICBT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_isel => (ALU, NONE, OP_ISEL, RA_OR_ZERO, RB, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_isync => (ALU, NONE, OP_ISYNC, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_lbarx => (LDST, NONE, OP_LOAD, RA_OR_ZERO, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '1', '0', '0', NONE, '0', '0', NONE),
|
||||
@@ -234,6 +237,8 @@ architecture behaviour of decode1 is
|
||||
INSN_lhzu => (LDST, NONE, OP_LOAD, RA_OR_ZERO, CONST_SI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '1', '0', '0', '0', NONE, '0', '0', DUPD),
|
||||
INSN_lhzux => (LDST, NONE, OP_LOAD, RA_OR_ZERO, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '1', '0', '0', '0', NONE, '0', '0', DUPD),
|
||||
INSN_lhzx => (LDST, NONE, OP_LOAD, RA_OR_ZERO, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_lq => (LDST, NONE, OP_LOAD, RA_OR_ZERO, CONST_DQ, NONE, RT, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', DRTP),
|
||||
INSN_lqarx => (LDST, NONE, OP_LOAD, RA_OR_ZERO, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '1', '0', '0', NONE, '0', '0', DRTP),
|
||||
INSN_lwa => (LDST, NONE, OP_LOAD, RA_OR_ZERO, CONST_DS, NONE, RT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '1', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_lwarx => (LDST, NONE, OP_LOAD, RA_OR_ZERO, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '1', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_lwaux => (LDST, NONE, OP_LOAD, RA_OR_ZERO, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '1', '1', '0', '0', '0', NONE, '0', '0', DUPD),
|
||||
@@ -281,12 +286,15 @@ architecture behaviour of decode1 is
|
||||
INSN_ori => (ALU, NONE, OP_LOGIC, NONE, CONST_UI, RS, RA, '0', '0', '1', '1', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE),
|
||||
INSN_oris => (ALU, NONE, OP_LOGIC, NONE, CONST_UI_HI, RS, RA, '0', '0', '1', '1', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE),
|
||||
INSN_paddi => (ALU, NONE, OP_ADD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_pdepd => (ALU, NONE, OP_BSORT, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_pextd => (ALU, NONE, OP_BSORT, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_plbz => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_pld => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_plfd => (LDST, FPU, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, FRT, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_plfs => (LDST, FPU, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, FRT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE),
|
||||
INSN_plha => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is2B, '0', '1', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_plhz => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_plq => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', DRTP),
|
||||
INSN_plwa => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '1', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_plwz => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_pnop => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
@@ -295,13 +303,15 @@ architecture behaviour of decode1 is
|
||||
INSN_pstfd => (LDST, FPU, OP_STORE, RA0_OR_CIA, CONST_PSI, FRS, NONE, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_pstfs => (LDST, FPU, OP_STORE, RA0_OR_CIA, CONST_PSI, FRS, NONE, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE),
|
||||
INSN_psth => (LDST, NONE, OP_STORE, RA0_OR_CIA, CONST_PSI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_pstq => (LDST, NONE, OP_STORE, RA0_OR_CIA, CONST_PSI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', DRSP),
|
||||
INSN_pstw => (LDST, NONE, OP_STORE, RA0_OR_CIA, CONST_PSI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_popcntb => (ALU, NONE, OP_POPCNT, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_popcntd => (ALU, NONE, OP_POPCNT, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_popcntw => (ALU, NONE, OP_POPCNT, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_popcntb => (ALU, NONE, OP_COUNTB, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_popcntd => (ALU, NONE, OP_COUNTB, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_popcntw => (ALU, NONE, OP_COUNTB, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_prtyd => (ALU, NONE, OP_PRTY, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_prtyw => (ALU, NONE, OP_PRTY, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_rfid => (ALU, NONE, OP_RFID, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_rfscv => (ALU, NONE, OP_RFID, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_rldcl => (ALU, NONE, OP_RLCL, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
INSN_rldcr => (ALU, NONE, OP_RLCR, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
INSN_rldic => (ALU, NONE, OP_RLC, NONE, CONST_SH, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
@@ -352,6 +362,8 @@ architecture behaviour of decode1 is
|
||||
INSN_sthu => (LDST, NONE, OP_STORE, RA_OR_ZERO, CONST_SI, RS, RA, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '1', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_sthux => (LDST, NONE, OP_STORE, RA_OR_ZERO, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '1', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_sthx => (LDST, NONE, OP_STORE, RA_OR_ZERO, RB, RS, NONE, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_stq => (LDST, NONE, OP_STORE, RA_OR_ZERO, CONST_DS, RS, NONE, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', DRSP),
|
||||
INSN_stqcx => (LDST, NONE, OP_STORE, RA_OR_ZERO, RB, RS, NONE, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '1', '0', '0', ONE, '0', '0', DRSP),
|
||||
INSN_stw => (LDST, NONE, OP_STORE, RA_OR_ZERO, CONST_SI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_stwbrx => (LDST, NONE, OP_STORE, RA_OR_ZERO, RB, RS, NONE, '0', '0', '0', '0', ZERO, '0', is4B, '1', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_stwcix => (LDST, NONE, OP_STORE, RA_OR_ZERO, RB, RS, NONE, '0', '0', '1', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
@@ -365,7 +377,7 @@ architecture behaviour of decode1 is
|
||||
INSN_subfic => (ALU, NONE, OP_ADD, RA, CONST_SI, NONE, RT, '0', '0', '1', '0', ONE, '1', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_subfme => (ALU, NONE, OP_ADD, RA, CONST_M1, NONE, RT, '0', '0', '1', '0', CA, '1', NONE, '0', '0', '0', '0', '0', '0', RCOE, '0', '0', NONE),
|
||||
INSN_subfze => (ALU, NONE, OP_ADD, RA, NONE, NONE, RT, '0', '0', '1', '0', CA, '1', NONE, '0', '0', '0', '0', '0', '0', RCOE, '0', '0', NONE),
|
||||
INSN_sync => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_sync => (LDST, NONE, OP_SYNC, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE),
|
||||
INSN_td => (ALU, NONE, OP_TRAP, RA, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_tdi => (ALU, NONE, OP_TRAP, RA, CONST_SI, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_tlbie => (LDST, NONE, OP_TLBIE, NONE, RB, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
@@ -373,7 +385,7 @@ architecture behaviour of decode1 is
|
||||
INSN_tlbsync => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_tw => (ALU, NONE, OP_TRAP, RA, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE),
|
||||
INSN_twi => (ALU, NONE, OP_TRAP, RA, CONST_SI, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE),
|
||||
INSN_wait => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_wait => (ALU, NONE, OP_WAIT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE),
|
||||
INSN_xor => (ALU, NONE, OP_XOR, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
|
||||
INSN_xori => (ALU, NONE, OP_XOR, NONE, CONST_UI, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
INSN_xoris => (ALU, NONE, OP_XOR, NONE, CONST_UI_HI, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
|
||||
@@ -384,7 +396,7 @@ architecture behaviour of decode1 is
|
||||
function decode_ram_spr(sprn : spr_num_t) return ram_spr_info is
|
||||
variable ret : ram_spr_info;
|
||||
begin
|
||||
ret := (index => (others => '0'), isodd => '0', valid => '1');
|
||||
ret := (index => (others => '0'), isodd => '0', is32b => '0', valid => '1');
|
||||
case sprn is
|
||||
when SPR_LR =>
|
||||
ret.index := RAMSPR_LR;
|
||||
@@ -418,6 +430,10 @@ architecture behaviour of decode1 is
|
||||
when SPR_HSPRG1 =>
|
||||
ret.index := RAMSPR_HSPRG1;
|
||||
ret.isodd := '1';
|
||||
when SPR_VRSAVE =>
|
||||
ret.index := RAMSPR_VRSAVE;
|
||||
ret.isodd := '1';
|
||||
ret.is32b := '1';
|
||||
when others =>
|
||||
ret.valid := '0';
|
||||
end case;
|
||||
@@ -427,9 +443,11 @@ architecture behaviour of decode1 is
|
||||
function map_spr(sprn : spr_num_t) return spr_id is
|
||||
variable i : spr_id;
|
||||
begin
|
||||
i.sel := "000";
|
||||
i.sel := "0000";
|
||||
i.valid := '1';
|
||||
i.ispmu := '0';
|
||||
i.ronly := '0';
|
||||
i.wonly := '0';
|
||||
case sprn is
|
||||
when SPR_TB =>
|
||||
i.sel := SPRSEL_TB;
|
||||
@@ -452,6 +470,24 @@ architecture behaviour of decode1 is
|
||||
i.sel := SPRSEL_CFAR;
|
||||
when SPR_XER =>
|
||||
i.sel := SPRSEL_XER;
|
||||
when SPR_FSCR =>
|
||||
i.sel := SPRSEL_FSCR;
|
||||
when SPR_HFSCR =>
|
||||
i.sel := SPRSEL_HFSCR;
|
||||
when SPR_HEIR =>
|
||||
i.sel := SPRSEL_HEIR;
|
||||
when SPR_CTRL =>
|
||||
i.sel := SPRSEL_CTRL;
|
||||
i.ronly := '1';
|
||||
when SPR_CTRLW =>
|
||||
i.sel := SPRSEL_CTRL;
|
||||
i.wonly := '1';
|
||||
when SPR_UDSCR =>
|
||||
i.sel := SPRSEL_DSCR;
|
||||
when SPR_DSCR =>
|
||||
i.sel := SPRSEL_DSCR;
|
||||
when SPR_PIR =>
|
||||
i.sel := SPRSEL_PIR;
|
||||
when others =>
|
||||
i.valid := '0';
|
||||
end case;
|
||||
@@ -459,6 +495,8 @@ architecture behaviour of decode1 is
|
||||
end;
|
||||
|
||||
begin
|
||||
double <= not r.second when (r.valid = '1' and decode.repeat /= NONE) else '0';
|
||||
|
||||
decode1_0: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
@@ -471,10 +509,15 @@ begin
|
||||
fetch_failed <= '0';
|
||||
pr <= prefix_state_init;
|
||||
elsif stall_in = '0' then
|
||||
r <= rin;
|
||||
fetch_failed <= f_in.fetch_failed;
|
||||
if f_in.valid = '1' then
|
||||
pr <= pr_in;
|
||||
if double = '0' then
|
||||
r <= rin;
|
||||
fetch_failed <= f_in.fetch_failed;
|
||||
if f_in.valid = '1' then
|
||||
pr <= pr_in;
|
||||
end if;
|
||||
else
|
||||
r.second <= '1';
|
||||
r.reg_c <= rin.reg_c;
|
||||
end if;
|
||||
end if;
|
||||
if rst = '1' then
|
||||
@@ -485,12 +528,12 @@ begin
|
||||
end if;
|
||||
end process;
|
||||
|
||||
busy_out <= stall_in;
|
||||
busy_out <= stall_in or double;
|
||||
|
||||
decode1_rom: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if stall_in = '0' then
|
||||
if stall_in = '0' and double = '0' then
|
||||
decode <= decode_rom(decode_rom_addr);
|
||||
end if;
|
||||
end if;
|
||||
@@ -521,7 +564,7 @@ begin
|
||||
v.big_endian := f_in.big_endian;
|
||||
|
||||
if is_X(f_in.insn) then
|
||||
v.spr_info := (sel => "XXX", others => 'X');
|
||||
v.spr_info := (sel => "XXXX", others => 'X');
|
||||
v.ram_spr := (index => (others => 'X'), others => 'X');
|
||||
else
|
||||
sprn := decode_spr_num(f_in.insn);
|
||||
@@ -620,33 +663,55 @@ begin
|
||||
-- Work out GPR/FPR read addresses
|
||||
-- Note that for prefixed instructions we are working this out based
|
||||
-- only on the suffix.
|
||||
maybe_rb := '0';
|
||||
vr.reg_1_addr := '0' & insn_ra(f_in.insn);
|
||||
vr.reg_2_addr := '0' & insn_rb(f_in.insn);
|
||||
vr.reg_3_addr := '0' & insn_rs(f_in.insn);
|
||||
if icode >= INSN_first_rb then
|
||||
maybe_rb := '1';
|
||||
if icode < INSN_first_frs then
|
||||
if icode >= INSN_first_rc then
|
||||
vr.reg_3_addr := '0' & insn_rcreg(f_in.insn);
|
||||
end if;
|
||||
else
|
||||
-- access FRS operand
|
||||
vr.reg_3_addr(5) := '1';
|
||||
if icode >= INSN_first_frab then
|
||||
-- access FRA and/or FRB operands
|
||||
vr.reg_1_addr(5) := '1';
|
||||
vr.reg_2_addr(5) := '1';
|
||||
end if;
|
||||
if icode >= INSN_first_frabc then
|
||||
-- access FRC operand
|
||||
vr.reg_3_addr := '1' & insn_rcreg(f_in.insn);
|
||||
if double = '0' then
|
||||
maybe_rb := '0';
|
||||
vr.reg_1_addr := '0' & insn_ra(f_in.insn);
|
||||
vr.reg_2_addr := '0' & insn_rb(f_in.insn);
|
||||
vr.reg_3_addr := '0' & insn_rs(f_in.insn);
|
||||
if icode >= INSN_first_rb then
|
||||
maybe_rb := '1';
|
||||
if icode < INSN_first_frs then
|
||||
if icode >= INSN_first_rc then
|
||||
vr.reg_3_addr := '0' & insn_rcreg(f_in.insn);
|
||||
end if;
|
||||
else
|
||||
-- access FRS operand
|
||||
vr.reg_3_addr(5) := '1';
|
||||
if icode >= INSN_first_frab then
|
||||
-- access FRA and/or FRB operands
|
||||
vr.reg_1_addr(5) := '1';
|
||||
vr.reg_2_addr(5) := '1';
|
||||
end if;
|
||||
if icode >= INSN_first_frabc then
|
||||
-- access FRC operand
|
||||
vr.reg_3_addr := '1' & insn_rcreg(f_in.insn);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
-- See if this is an instruction where repeat_t = DRSP and we need
|
||||
-- to read RS|1 followed by RS, i.e. stq or stqcx. in LE mode
|
||||
-- (note we don't have access to the decode for the current instruction)
|
||||
if (icode = INSN_stq or icode = INSN_stqcx) and f_in.big_endian = '0' then
|
||||
vr.reg_3_addr(0) := '1';
|
||||
end if;
|
||||
vr.read_1_enable := f_in.valid;
|
||||
vr.read_2_enable := f_in.valid and maybe_rb;
|
||||
vr.read_3_enable := f_in.valid;
|
||||
else
|
||||
-- second instance of a doubled instruction
|
||||
vr.reg_1_addr := r.reg_a;
|
||||
vr.reg_2_addr := r.reg_b;
|
||||
vr.reg_3_addr := r.reg_c;
|
||||
vr.read_1_enable := '0'; -- (not actually used)
|
||||
vr.read_2_enable := '0';
|
||||
vr.read_3_enable := '1'; -- (not actually used)
|
||||
-- For pstq, and for stq and stqcx in BE mode,
|
||||
-- we need to read register RS|1 in the cycle after we read RS;
|
||||
-- stq and stqcx in LE mode read RS.
|
||||
if decode.repeat = DRSP then
|
||||
vr.reg_3_addr(0) := r.prefixed or f_in.big_endian;
|
||||
end if;
|
||||
end if;
|
||||
vr.read_1_enable := f_in.valid;
|
||||
vr.read_2_enable := f_in.valid and maybe_rb;
|
||||
vr.read_3_enable := f_in.valid;
|
||||
|
||||
v.reg_a := vr.reg_1_addr;
|
||||
v.reg_b := vr.reg_2_addr;
|
||||
|
||||
102
decode2.vhdl
102
decode2.vhdl
@@ -232,12 +232,13 @@ architecture behaviour of decode2 is
|
||||
);
|
||||
|
||||
constant subresult_select : mux_select_array_t := (
|
||||
OP_MUL_L64 => "000", -- muldiv_result
|
||||
OP_MUL_H64 => "001",
|
||||
OP_MUL_H32 => "010",
|
||||
OP_DIV => "011",
|
||||
OP_DIVE => "011",
|
||||
OP_MOD => "011",
|
||||
OP_MUL_L64 => "000", -- multicyc_result
|
||||
OP_MUL_H64 => "010",
|
||||
OP_MUL_H32 => "001",
|
||||
OP_DIV => "101",
|
||||
OP_DIVE => "101",
|
||||
OP_MOD => "101",
|
||||
OP_BSORT => "100",
|
||||
OP_ADDG6S => "001", -- misc_result
|
||||
OP_ISEL => "010",
|
||||
OP_DARN => "011",
|
||||
@@ -347,7 +348,8 @@ begin
|
||||
elsif deferred = '0' then
|
||||
if dc2in.e.valid = '1' then
|
||||
report "execute " & to_hstring(dc2in.e.nia) &
|
||||
" tag=" & integer'image(dc2in.e.instr_tag.tag) & std_ulogic'image(dc2in.e.instr_tag.valid);
|
||||
" tag=" & integer'image(dc2in.e.instr_tag.tag) & std_ulogic'image(dc2in.e.instr_tag.valid) &
|
||||
" rpt=" & std_ulogic'image(dc2in.e.repeat) & " 2nd=" & std_ulogic'image(dc2in.e.second) & " wr=" & to_hstring(dc2in.e.write_reg);
|
||||
end if;
|
||||
dc2 <= dc2in;
|
||||
elsif dc2.read_rspr = '0' then
|
||||
@@ -376,6 +378,31 @@ begin
|
||||
dec_b := decode_input_reg_b (d_in.decode.input_reg_b, d_in.insn, d_in.prefix);
|
||||
dec_c := decode_input_reg_c (d_in.decode.input_reg_c, d_in.insn);
|
||||
dec_o := decode_output_reg (d_in.decode.output_reg_a, d_in.insn);
|
||||
case d_in.decode.repeat is
|
||||
when DUPD =>
|
||||
if d_in.second = '1' then
|
||||
-- update-form loads, 2nd instruction writes RA
|
||||
dec_o.reg := dec_a.reg;
|
||||
end if;
|
||||
when DRSP =>
|
||||
-- non-prefixed stq, stqcx do RS|1, RS in LE mode; others do RS, RS|1
|
||||
if d_in.second = (d_in.big_endian or d_in.prefixed) then
|
||||
dec_c.reg(0) := '1'; -- do RS, RS|1
|
||||
end if;
|
||||
when DRTP =>
|
||||
-- non-prefixed lq, lqarx do RT|1, RT in LE mode; others do RT, RT|1
|
||||
if d_in.second = (d_in.big_endian or d_in.prefixed) then
|
||||
dec_o.reg(0) := '1';
|
||||
end if;
|
||||
when others =>
|
||||
end case;
|
||||
-- For the second instance of a doubled instruction, we ignore the RA
|
||||
-- and RB operands, in order to avoid false dependencies on the output
|
||||
-- of the first instance.
|
||||
if d_in.second = '1' then
|
||||
dec_a.reg_valid := '0';
|
||||
dec_b.reg_valid := '0';
|
||||
end if;
|
||||
if d_in.valid = '0' or d_in.illegal_suffix = '1' then
|
||||
dec_a.reg_valid := '0';
|
||||
dec_b.reg_valid := '0';
|
||||
@@ -420,6 +447,8 @@ begin
|
||||
v.e.input_cr := d_in.decode.input_cr;
|
||||
v.e.output_cr := d_in.decode.output_cr;
|
||||
|
||||
v.e.spr_select := d_in.spr_info;
|
||||
|
||||
-- Work out whether XER SO/OV/OV32 bits are set
|
||||
-- or used by this instruction
|
||||
v.e.rc := decode_rc(d_in.decode.rc, d_in.insn);
|
||||
@@ -450,8 +479,15 @@ begin
|
||||
v.input_ov := '1';
|
||||
when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR =>
|
||||
unit := LDST;
|
||||
when SPR_TAR =>
|
||||
v.e.uses_tar := '1';
|
||||
when SPR_UDSCR =>
|
||||
v.e.uses_dscr := '1';
|
||||
when others =>
|
||||
end case;
|
||||
if d_in.spr_info.wonly = '1' then
|
||||
v.e.spr_select.valid := '0';
|
||||
end if;
|
||||
end if;
|
||||
when OP_MTSPR =>
|
||||
if is_X(d_in.insn) then
|
||||
@@ -468,9 +504,15 @@ begin
|
||||
if d_in.valid = '1' then
|
||||
v.sgl_pipe := '1';
|
||||
end if;
|
||||
when SPR_TAR =>
|
||||
v.e.uses_tar := '1';
|
||||
when SPR_UDSCR =>
|
||||
v.e.uses_dscr := '1';
|
||||
when others =>
|
||||
end case;
|
||||
if d_in.spr_info.valid = '1' and d_in.valid = '1' then
|
||||
if d_in.spr_info.ronly = '1' then
|
||||
v.e.spr_select.valid := '0';
|
||||
elsif d_in.spr_info.valid = '1' and d_in.valid = '1' then
|
||||
v.sgl_pipe := '1';
|
||||
end if;
|
||||
end if;
|
||||
@@ -496,12 +538,10 @@ begin
|
||||
end if;
|
||||
v.e.dec_ctr := decctr;
|
||||
|
||||
v.repeat := d_in.decode.repeat;
|
||||
if d_in.decode.repeat /= NONE then
|
||||
v.e.repeat := '1';
|
||||
end if;
|
||||
|
||||
v.e.spr_select := d_in.spr_info;
|
||||
v.e.second := d_in.second;
|
||||
|
||||
if decctr = '1' then
|
||||
-- read and write CTR
|
||||
@@ -525,12 +565,14 @@ begin
|
||||
v.e.ramspr_rd_odd := '1';
|
||||
else
|
||||
v.e.ramspr_even_rdaddr := RAMSPR_TAR;
|
||||
v.e.uses_tar := '1';
|
||||
end if;
|
||||
sprs_busy := '1';
|
||||
when OP_MFSPR =>
|
||||
v.e.ramspr_even_rdaddr := d_in.ram_spr.index;
|
||||
v.e.ramspr_odd_rdaddr := d_in.ram_spr.index;
|
||||
v.e.ramspr_rd_odd := d_in.ram_spr.isodd;
|
||||
v.e.ramspr_32bit := d_in.ram_spr.is32b;
|
||||
v.e.spr_is_ram := d_in.ram_spr.valid;
|
||||
sprs_busy := d_in.ram_spr.valid;
|
||||
when OP_MTSPR =>
|
||||
@@ -539,8 +581,19 @@ begin
|
||||
v.e.ramspr_write_odd := d_in.ram_spr.valid and d_in.ram_spr.isodd;
|
||||
v.e.spr_is_ram := d_in.ram_spr.valid;
|
||||
when OP_RFID =>
|
||||
v.e.ramspr_even_rdaddr := RAMSPR_SRR0;
|
||||
v.e.ramspr_odd_rdaddr := RAMSPR_SRR1;
|
||||
if d_in.insn(7) = '1' then
|
||||
-- rfscv
|
||||
v.e.ramspr_even_rdaddr := RAMSPR_LR;
|
||||
v.e.ramspr_odd_rdaddr := RAMSPR_CTR;
|
||||
elsif d_in.insn(9) = '0' then
|
||||
-- rfid
|
||||
v.e.ramspr_even_rdaddr := RAMSPR_SRR0;
|
||||
v.e.ramspr_odd_rdaddr := RAMSPR_SRR1;
|
||||
else
|
||||
-- hrfid
|
||||
v.e.ramspr_even_rdaddr := RAMSPR_HSRR0;
|
||||
v.e.ramspr_odd_rdaddr := RAMSPR_HSRR1;
|
||||
end if;
|
||||
sprs_busy := '1';
|
||||
when others =>
|
||||
end case;
|
||||
@@ -590,23 +643,28 @@ begin
|
||||
if op = OP_MFSPR then
|
||||
if d_in.ram_spr.valid = '1' then
|
||||
v.e.result_sel := "101"; -- ramspr_result
|
||||
elsif d_in.spr_info.valid = '0' then
|
||||
elsif d_in.spr_info.valid = '0' or d_in.spr_info.wonly = '1' then
|
||||
-- Privileged mfspr to invalid/unimplemented SPR numbers
|
||||
-- writes the contents of RT back to RT (i.e. it's a no-op)
|
||||
v.e.result_sel := "001"; -- logical_result
|
||||
end if;
|
||||
end if;
|
||||
v.e.prefixed := d_in.prefixed;
|
||||
v.e.prefix := d_in.prefix;
|
||||
v.e.illegal_suffix := d_in.illegal_suffix;
|
||||
v.e.misaligned_prefix := d_in.misaligned_prefix;
|
||||
|
||||
elsif dc2.e.valid = '1' then
|
||||
-- dc2.busy = 1 and dc2.e.valid = 1, thus this must be a repeated instruction.
|
||||
-- Set up for the second iteration (if deferred = 1 this will all be ignored)
|
||||
v.e.second := '1';
|
||||
-- DUPD is the only possibility here:
|
||||
-- update-form loads, 2nd instruction writes RA
|
||||
v.e.write_reg := dc2.e.read_reg1;
|
||||
-- check for invalid forms that cause an illegal instruction interrupt
|
||||
-- Does RA = RT for a load quadword instr, or RB = RT for lqarx?
|
||||
if d_in.decode.repeat = DRTP and
|
||||
(insn_ra(d_in.insn) = insn_rt(d_in.insn) or
|
||||
(d_in.decode.reserve = '1' and insn_rb(d_in.insn) = insn_rt(d_in.insn))) then
|
||||
v.e.illegal_form := '1';
|
||||
end if;
|
||||
-- Is RS/RT odd for a load/store quadword instruction?
|
||||
if (d_in.decode.repeat = DRSP or d_in.decode.repeat = DRTP) and d_in.insn(21) = '1' then
|
||||
v.e.illegal_form := '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- issue control
|
||||
@@ -695,7 +753,7 @@ begin
|
||||
|
||||
v.e.valid := control_valid_out;
|
||||
v.e.instr_tag := instr_tag;
|
||||
v.busy := valid_in and (not control_valid_out or (v.e.repeat and not v.e.second));
|
||||
v.busy := valid_in and not control_valid_out;
|
||||
|
||||
stall_out <= dc2.busy or deferred;
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@ package decode_types is
|
||||
OP_ATTN, OP_B, OP_BC, OP_BCREG,
|
||||
OP_BCD, OP_BPERM, OP_BREV,
|
||||
OP_CMP, OP_CMPB, OP_CMPEQB, OP_CMPRB,
|
||||
OP_CNTZ, OP_CROP,
|
||||
OP_DARN, OP_DCBF, OP_DCBST, OP_DCBT, OP_DCBTST,
|
||||
OP_DCBZ, OP_ICBI, OP_ICBT,
|
||||
OP_COUNTB, OP_CROP,
|
||||
OP_DARN, OP_DCBF, OP_DCBST, OP_DCBZ,
|
||||
OP_SPARE,
|
||||
OP_ICBI, OP_ICBT,
|
||||
OP_FP_CMP, OP_FP_ARITH, OP_FP_MOVE, OP_FP_MISC,
|
||||
OP_DIV, OP_DIVE, OP_MOD,
|
||||
OP_EXTS, OP_EXTSWSLI,
|
||||
@@ -18,12 +19,14 @@ package decode_types is
|
||||
OP_MCRXRX, OP_MFCR, OP_MFMSR, OP_MFSPR,
|
||||
OP_MTCRF, OP_MTMSRD, OP_MTSPR, OP_MUL_L64,
|
||||
OP_MUL_H64, OP_MUL_H32,
|
||||
OP_POPCNT, OP_PRTY, OP_RFID,
|
||||
OP_BSORT,
|
||||
OP_PRTY, OP_RFID,
|
||||
OP_RLC, OP_RLCL, OP_RLCR, OP_SC, OP_SETB,
|
||||
OP_SHL, OP_SHR,
|
||||
OP_SYNC, OP_TLBIE, OP_TRAP,
|
||||
OP_XOR,
|
||||
OP_ADDG6S,
|
||||
OP_WAIT,
|
||||
OP_FETCH_FAILED
|
||||
);
|
||||
|
||||
@@ -106,6 +109,7 @@ package decode_types is
|
||||
INSN_prtyw,
|
||||
INSN_prtyd, -- 70
|
||||
INSN_rfid,
|
||||
INSN_rfscv,
|
||||
INSN_rldic,
|
||||
INSN_rldicl,
|
||||
INSN_rldicr,
|
||||
@@ -113,8 +117,8 @@ package decode_types is
|
||||
INSN_rlwimi,
|
||||
INSN_rlwinm,
|
||||
INSN_rnop,
|
||||
INSN_sc,
|
||||
INSN_setb, -- 80
|
||||
INSN_sc, -- 80
|
||||
INSN_setb,
|
||||
INSN_slbia,
|
||||
INSN_sradi,
|
||||
INSN_srawi,
|
||||
@@ -122,9 +126,10 @@ package decode_types is
|
||||
INSN_std,
|
||||
INSN_stdu,
|
||||
INSN_sthu,
|
||||
INSN_stwu,
|
||||
INSN_stq,
|
||||
INSN_stwu, -- 90
|
||||
INSN_subfic,
|
||||
INSN_subfme, -- 90
|
||||
INSN_subfme,
|
||||
INSN_subfze,
|
||||
INSN_sync,
|
||||
INSN_tdi,
|
||||
@@ -132,23 +137,23 @@ package decode_types is
|
||||
INSN_twi,
|
||||
INSN_wait,
|
||||
INSN_xori,
|
||||
INSN_xoris,
|
||||
-- pad to 104
|
||||
INSN_063, INSN_064, INSN_065, INSN_066, INSN_067,
|
||||
INSN_xoris, -- 100
|
||||
-- pad to 102
|
||||
INSN_065,
|
||||
|
||||
-- Non-prefixed instructions that have a MLS:D prefixed form and
|
||||
-- their corresponding prefixed instructions.
|
||||
-- The non-prefixed versions have even indexes so that we can
|
||||
-- convert them to the prefixed version by setting bit 0
|
||||
INSN_addi, -- 104
|
||||
INSN_addi, -- 102
|
||||
INSN_paddi,
|
||||
INSN_lbz,
|
||||
INSN_plbz,
|
||||
INSN_lha,
|
||||
INSN_plha,
|
||||
INSN_lhz, -- 110
|
||||
INSN_lhz,
|
||||
INSN_plhz,
|
||||
INSN_lwz,
|
||||
INSN_lwz, -- 110
|
||||
INSN_plwz,
|
||||
INSN_stb,
|
||||
INSN_pstb,
|
||||
@@ -158,15 +163,18 @@ package decode_types is
|
||||
INSN_pstw,
|
||||
|
||||
-- Slots for non-prefixed opcodes that are 8LS:D when prefixed
|
||||
INSN_lhzu, -- 120
|
||||
INSN_lhzu,
|
||||
INSN_plwa,
|
||||
INSN_lq, -- 120
|
||||
INSN_plq,
|
||||
INSN_op57,
|
||||
INSN_pld,
|
||||
INSN_op60,
|
||||
INSN_pstq,
|
||||
INSN_op61,
|
||||
INSN_pstd,
|
||||
|
||||
-- pad to 128 to simplify comparison logic
|
||||
INSN_07e, INSN_07f,
|
||||
|
||||
-- The following instructions have an RB operand but don't access FPRs
|
||||
INSN_add,
|
||||
@@ -177,11 +185,12 @@ package decode_types is
|
||||
INSN_and,
|
||||
INSN_andc,
|
||||
INSN_bperm,
|
||||
INSN_cfuged,
|
||||
INSN_cmp,
|
||||
INSN_cmpb,
|
||||
INSN_cmpeqb,
|
||||
INSN_cmpl,
|
||||
INSN_cmprb, -- 140
|
||||
INSN_cmpl, -- 140
|
||||
INSN_cmprb,
|
||||
INSN_dcbf,
|
||||
INSN_dcbst,
|
||||
INSN_dcbt,
|
||||
@@ -190,8 +199,8 @@ package decode_types is
|
||||
INSN_divd,
|
||||
INSN_divdu,
|
||||
INSN_divde,
|
||||
INSN_divdeu,
|
||||
INSN_divw, -- 150
|
||||
INSN_divdeu, -- 150
|
||||
INSN_divw,
|
||||
INSN_divwu,
|
||||
INSN_divwe,
|
||||
INSN_divweu,
|
||||
@@ -200,8 +209,8 @@ package decode_types is
|
||||
INSN_icbt,
|
||||
INSN_isel,
|
||||
INSN_lbarx,
|
||||
INSN_lbzcix,
|
||||
INSN_lbzux, -- 160
|
||||
INSN_lbzcix, -- 160
|
||||
INSN_lbzux,
|
||||
INSN_lbzx,
|
||||
INSN_ldarx,
|
||||
INSN_ldbrx,
|
||||
@@ -210,18 +219,19 @@ package decode_types is
|
||||
INSN_ldux,
|
||||
INSN_lharx,
|
||||
INSN_lhax,
|
||||
INSN_lhaux,
|
||||
INSN_lhbrx, -- 170
|
||||
INSN_lhaux, -- 170
|
||||
INSN_lhbrx,
|
||||
INSN_lhzcix,
|
||||
INSN_lhzx,
|
||||
INSN_lhzux,
|
||||
INSN_lqarx,
|
||||
INSN_lwarx,
|
||||
INSN_lwax,
|
||||
INSN_lwaux,
|
||||
INSN_lwbrx,
|
||||
INSN_lwzcix,
|
||||
INSN_lwzcix, -- 180
|
||||
INSN_lwzx,
|
||||
INSN_lwzux, -- 180
|
||||
INSN_lwzux,
|
||||
INSN_modsd,
|
||||
INSN_modsw,
|
||||
INSN_moduw,
|
||||
@@ -229,52 +239,55 @@ package decode_types is
|
||||
INSN_mulhw,
|
||||
INSN_mulhwu,
|
||||
INSN_mulhd,
|
||||
INSN_mulhdu,
|
||||
INSN_mulhdu, -- 190
|
||||
INSN_mullw,
|
||||
INSN_mulld, -- 190
|
||||
INSN_mulld,
|
||||
INSN_nand,
|
||||
INSN_nor,
|
||||
INSN_or,
|
||||
INSN_orc,
|
||||
INSN_pdepd,
|
||||
INSN_pextd,
|
||||
INSN_rldcl,
|
||||
INSN_rldcr,
|
||||
INSN_rldcr, -- 200
|
||||
INSN_rlwnm,
|
||||
INSN_slw,
|
||||
INSN_sld,
|
||||
INSN_sraw, -- 200
|
||||
INSN_sraw,
|
||||
INSN_srad,
|
||||
INSN_srw,
|
||||
INSN_srd,
|
||||
INSN_stbcix,
|
||||
INSN_stbcx,
|
||||
INSN_stbx,
|
||||
INSN_stbx, -- 210
|
||||
INSN_stbux,
|
||||
INSN_stdbrx,
|
||||
INSN_stdcix,
|
||||
INSN_stdcx, -- 210
|
||||
INSN_stdcx,
|
||||
INSN_stdx,
|
||||
INSN_stdux,
|
||||
INSN_sthbrx,
|
||||
INSN_sthcix,
|
||||
INSN_sthcx,
|
||||
INSN_sthx,
|
||||
INSN_sthx, -- 220
|
||||
INSN_sthux,
|
||||
INSN_stqcx,
|
||||
INSN_stwbrx,
|
||||
INSN_stwcix,
|
||||
INSN_stwcx, -- 220
|
||||
INSN_stwcx,
|
||||
INSN_stwx,
|
||||
INSN_stwux,
|
||||
INSN_subf,
|
||||
INSN_subfc,
|
||||
INSN_subfe,
|
||||
INSN_subfe, -- 230
|
||||
INSN_td,
|
||||
INSN_tlbie,
|
||||
INSN_tlbiel,
|
||||
INSN_tw,
|
||||
INSN_xor, -- 230
|
||||
INSN_xor,
|
||||
|
||||
-- pad to 232 to simplify comparison logic
|
||||
INSN_231,
|
||||
-- pad to 240 to simplify comparison logic
|
||||
INSN_236, INSN_237, INSN_238, INSN_239,
|
||||
|
||||
-- The following instructions have a third input addressed by RC
|
||||
INSN_maddld,
|
||||
@@ -282,9 +295,7 @@ package decode_types is
|
||||
INSN_maddhdu,
|
||||
|
||||
-- pad to 256 to simplify comparison logic
|
||||
INSN_235,
|
||||
INSN_236, INSN_237, INSN_238, INSN_239,
|
||||
INSN_240, INSN_241, INSN_242, INSN_243,
|
||||
INSN_243,
|
||||
INSN_244, INSN_245, INSN_246, INSN_247,
|
||||
INSN_248, INSN_249, INSN_250, INSN_251,
|
||||
INSN_252, INSN_253, INSN_254, INSN_255,
|
||||
@@ -434,7 +445,9 @@ package decode_types is
|
||||
type length_t is (NONE, is1B, is2B, is4B, is8B);
|
||||
|
||||
type repeat_t is (NONE, -- instruction is not repeated
|
||||
DUPD); -- update-form load
|
||||
DUPD, -- update-form load
|
||||
DRSP, -- double RS (RS, RS+1)
|
||||
DRTP); -- double RT (RT, RT+1, or RT+1, RT)
|
||||
|
||||
type decode_rom_t is record
|
||||
unit : unit_t;
|
||||
@@ -518,6 +531,7 @@ package body decode_types is
|
||||
when INSN_lhau => return "101011";
|
||||
when INSN_lhz => return "101000";
|
||||
when INSN_lhzu => return "101001";
|
||||
when INSN_lq => return "111000";
|
||||
when INSN_lwz => return "100000";
|
||||
when INSN_lwzu => return "100001";
|
||||
when INSN_mulli => return "000111";
|
||||
@@ -537,6 +551,7 @@ package body decode_types is
|
||||
when INSN_sth => return "101100";
|
||||
when INSN_sthu => return "101101";
|
||||
when INSN_stw => return "100100";
|
||||
when INSN_stq => return "111110";
|
||||
when INSN_stwu => return "100101";
|
||||
when INSN_subfic => return "001000";
|
||||
when INSN_tdi => return "000010";
|
||||
@@ -582,6 +597,7 @@ package body decode_types is
|
||||
when INSN_fnmadd => return "111111";
|
||||
when INSN_prefix => return "000001";
|
||||
when INSN_op57 => return "111001";
|
||||
when INSN_op60 => return "111100";
|
||||
when INSN_op61 => return "111101";
|
||||
when INSN_add => return "011111";
|
||||
when INSN_addc => return "011111";
|
||||
@@ -649,6 +665,7 @@ package body decode_types is
|
||||
when INSN_lhzcix => return "011111";
|
||||
when INSN_lhzux => return "011111";
|
||||
when INSN_lhzx => return "011111";
|
||||
when INSN_lqarx => return "011111";
|
||||
when INSN_lwarx => return "011111";
|
||||
when INSN_lwaux => return "011111";
|
||||
when INSN_lwax => return "011111";
|
||||
@@ -714,6 +731,7 @@ package body decode_types is
|
||||
when INSN_sthcx => return "011111";
|
||||
when INSN_sthux => return "011111";
|
||||
when INSN_sthx => return "011111";
|
||||
when INSN_stqcx => return "011111";
|
||||
when INSN_stwbrx => return "011111";
|
||||
when INSN_stwcix => return "011111";
|
||||
when INSN_stwcx => return "011111";
|
||||
|
||||
375
execute1.vhdl
375
execute1.vhdl
@@ -15,6 +15,7 @@ entity execute1 is
|
||||
SIM : boolean := false;
|
||||
EX1_BYPASS : boolean := true;
|
||||
HAS_FPU : boolean := true;
|
||||
CPU_INDEX : natural;
|
||||
-- Non-zero to enable log data collection
|
||||
LOG_LENGTH : natural := 0
|
||||
);
|
||||
@@ -45,6 +46,7 @@ entity execute1 is
|
||||
|
||||
dbg_ctrl_out : out ctrl_t;
|
||||
|
||||
run_out : out std_ulogic;
|
||||
icache_inval : out std_ulogic;
|
||||
terminate_out : out std_ulogic;
|
||||
|
||||
@@ -79,12 +81,23 @@ architecture behaviour of execute1 is
|
||||
write_xerlow : std_ulogic;
|
||||
write_dec : std_ulogic;
|
||||
write_cfar : std_ulogic;
|
||||
set_cfar : std_ulogic;
|
||||
write_loga : std_ulogic;
|
||||
inc_loga : std_ulogic;
|
||||
write_pmuspr : std_ulogic;
|
||||
ramspr_write_even : std_ulogic;
|
||||
ramspr_write_odd : std_ulogic;
|
||||
mult_32s : std_ulogic;
|
||||
write_fscr : std_ulogic;
|
||||
write_ic : std_ulogic;
|
||||
write_hfscr : std_ulogic;
|
||||
write_hic : std_ulogic;
|
||||
write_heir : std_ulogic;
|
||||
set_heir : std_ulogic;
|
||||
write_ctrl : std_ulogic;
|
||||
write_dscr : std_ulogic;
|
||||
enter_wait : std_ulogic;
|
||||
scv_trap : std_ulogic;
|
||||
end record;
|
||||
constant side_effect_init : side_effect_type := (others => '0');
|
||||
|
||||
@@ -101,16 +114,18 @@ architecture behaviour of execute1 is
|
||||
direct_branch : std_ulogic;
|
||||
start_mul : std_ulogic;
|
||||
start_div : std_ulogic;
|
||||
start_bsort : std_ulogic;
|
||||
do_trace : std_ulogic;
|
||||
fp_intr : std_ulogic;
|
||||
res2_sel : std_ulogic_vector(1 downto 0);
|
||||
bypass_valid : std_ulogic;
|
||||
ramspr_odd_data : std_ulogic_vector(63 downto 0);
|
||||
ic : std_ulogic_vector(3 downto 0);
|
||||
end record;
|
||||
constant actions_type_init : actions_type :=
|
||||
(e => Execute1ToWritebackInit, se => side_effect_init,
|
||||
new_msr => (others => '0'), res2_sel => "00",
|
||||
ramspr_odd_data => 64x"0", others => '0');
|
||||
ramspr_odd_data => 64x"0", ic => x"0", others => '0');
|
||||
|
||||
type reg_stage1_type is record
|
||||
e : Execute1ToWritebackType;
|
||||
@@ -121,7 +136,7 @@ architecture behaviour of execute1 is
|
||||
prev_op : insn_type_t;
|
||||
prev_prefixed : std_ulogic;
|
||||
oe : std_ulogic;
|
||||
mul_select : std_ulogic_vector(1 downto 0);
|
||||
mul_select : std_ulogic_vector(2 downto 0);
|
||||
res2_sel : std_ulogic_vector(1 downto 0);
|
||||
spr_select : spr_id;
|
||||
pmu_spr_num : std_ulogic_vector(4 downto 0);
|
||||
@@ -131,6 +146,7 @@ architecture behaviour of execute1 is
|
||||
mul_in_progress : std_ulogic;
|
||||
mul_finish : std_ulogic;
|
||||
div_in_progress : std_ulogic;
|
||||
bsort_in_progress : std_ulogic;
|
||||
no_instr_avail : std_ulogic;
|
||||
instr_dispatch : std_ulogic;
|
||||
ext_interrupt : std_ulogic;
|
||||
@@ -141,21 +157,28 @@ architecture behaviour of execute1 is
|
||||
xerc_valid : std_ulogic;
|
||||
ramspr_wraddr : ramspr_index;
|
||||
ramspr_odd_data : std_ulogic_vector(63 downto 0);
|
||||
ic : std_ulogic_vector(3 downto 0);
|
||||
prefixed : std_ulogic;
|
||||
insn : std_ulogic_vector(31 downto 0);
|
||||
prefix : std_ulogic_vector(25 downto 0);
|
||||
end record;
|
||||
constant reg_stage1_type_init : reg_stage1_type :=
|
||||
(e => Execute1ToWritebackInit, se => side_effect_init,
|
||||
busy => '0',
|
||||
fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL,
|
||||
prev_prefixed => '0',
|
||||
oe => '0', mul_select => "00", res2_sel => "00",
|
||||
oe => '0', mul_select => "000", res2_sel => "00",
|
||||
spr_select => spr_id_init, pmu_spr_num => 5x"0",
|
||||
redir_to_next => '0', advance_nia => '0', lr_from_next => '0',
|
||||
mul_in_progress => '0', mul_finish => '0', div_in_progress => '0',
|
||||
bsort_in_progress => '0',
|
||||
no_instr_avail => '0', instr_dispatch => '0', ext_interrupt => '0',
|
||||
taken_branch_event => '0', br_mispredict => '0',
|
||||
msr => 64x"0",
|
||||
xerc => xerc_init, xerc_valid => '0',
|
||||
ramspr_wraddr => (others => '0'), ramspr_odd_data => 64x"0");
|
||||
ramspr_wraddr => (others => '0'), ramspr_odd_data => 64x"0",
|
||||
ic => x"0",
|
||||
prefixed => '0', insn => 32x"0", prefix => 26x"0");
|
||||
|
||||
type reg_stage2_type is record
|
||||
e : Execute1ToWritebackType;
|
||||
@@ -190,7 +213,8 @@ architecture behaviour of execute1 is
|
||||
signal alu_result: std_ulogic_vector(63 downto 0);
|
||||
signal adder_result: std_ulogic_vector(63 downto 0);
|
||||
signal misc_result: std_ulogic_vector(63 downto 0);
|
||||
signal muldiv_result: std_ulogic_vector(63 downto 0);
|
||||
signal multicyc_result: std_ulogic_vector(63 downto 0);
|
||||
signal bsort_result: std_ulogic_vector(63 downto 0);
|
||||
signal spr_result: std_ulogic_vector(63 downto 0);
|
||||
signal next_nia : std_ulogic_vector(63 downto 0);
|
||||
signal s1_sel : std_ulogic_vector(2 downto 0);
|
||||
@@ -215,6 +239,10 @@ architecture behaviour of execute1 is
|
||||
signal x_to_divider: Execute1ToDividerType;
|
||||
signal divider_to_x: DividerToExecute1Type := DividerToExecute1Init;
|
||||
|
||||
-- bit-sort unit signals
|
||||
signal bsort_start : std_ulogic;
|
||||
signal bsort_done : std_ulogic;
|
||||
|
||||
-- random number generator signals
|
||||
signal random_raw : std_ulogic_vector(63 downto 0);
|
||||
signal random_cond : std_ulogic_vector(63 downto 0);
|
||||
@@ -322,6 +350,7 @@ architecture behaviour of execute1 is
|
||||
-- 48:63, and partial function MSR bits lie in the range
|
||||
-- 33:36 and 42:47. (Note this is IBM bit numbering).
|
||||
msr_out := (others => '0');
|
||||
msr_out(MSR_HV) := '1'; -- HV is always set
|
||||
msr_out(63 downto 31) := msr(63 downto 31);
|
||||
msr_out(26 downto 22) := msr(26 downto 22);
|
||||
msr_out(15 downto 0) := msr(15 downto 0);
|
||||
@@ -332,6 +361,9 @@ architecture behaviour of execute1 is
|
||||
return std_ulogic_vector is
|
||||
variable srr1: std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
srr1(63 downto 61) := msr(63 downto 61);
|
||||
srr1(MSR_HV) := '1';
|
||||
srr1(59 downto 31) := msr(59 downto 31);
|
||||
srr1(63 downto 31) := msr(63 downto 31);
|
||||
srr1(30 downto 27) := flags(14 downto 11);
|
||||
srr1(26 downto 22) := msr(26 downto 22);
|
||||
@@ -365,6 +397,39 @@ architecture behaviour of execute1 is
|
||||
xerc.ov32 & xerc.ca32 & xer_low(17 downto 0);
|
||||
end;
|
||||
|
||||
function assemble_fscr(c: ctrl_t) return std_ulogic_vector is
|
||||
variable ret : std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
ret := (others => '0');
|
||||
ret(59 downto 56) := c.fscr_ic;
|
||||
ret(FSCR_PREFIX) := c.fscr_pref;
|
||||
ret(FSCR_SCV) := c.fscr_scv;
|
||||
ret(FSCR_TAR) := c.fscr_tar;
|
||||
ret(FSCR_DSCR) := c.fscr_dscr;
|
||||
return ret;
|
||||
end;
|
||||
|
||||
function assemble_hfscr(c: ctrl_t) return std_ulogic_vector is
|
||||
variable ret : std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
ret := (others => '0');
|
||||
ret(59 downto 56) := c.hfscr_ic;
|
||||
ret(HFSCR_PREFIX) := c.hfscr_pref;
|
||||
ret(HFSCR_TAR) := c.hfscr_tar;
|
||||
ret(HFSCR_DSCR) := c.hfscr_dscr;
|
||||
ret(HFSCR_FP) := c.hfscr_fp;
|
||||
return ret;
|
||||
end;
|
||||
|
||||
function assemble_ctrl(c: ctrl_t; msrpr: std_ulogic) return std_ulogic_vector is
|
||||
variable ret : std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
ret := (others => '0');
|
||||
ret(0) := c.run;
|
||||
ret(15) := c.run and not msrpr;
|
||||
return ret;
|
||||
end;
|
||||
|
||||
-- Tell vivado to keep the hierarchy for the random module so that the
|
||||
-- net names in the xdc file match.
|
||||
attribute keep_hierarchy : string;
|
||||
@@ -437,6 +502,18 @@ begin
|
||||
);
|
||||
end generate;
|
||||
|
||||
bsort_0: entity work.bit_sorter
|
||||
port map (
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
rs => c_in,
|
||||
rb => b_in,
|
||||
go => bsort_start,
|
||||
opc => e_in.insn(7 downto 6),
|
||||
done => bsort_done,
|
||||
result => bsort_result
|
||||
);
|
||||
|
||||
random_0: entity work.random
|
||||
port map (
|
||||
clk => clk,
|
||||
@@ -484,7 +561,7 @@ begin
|
||||
x_to_pmu.addr_v <= '0';
|
||||
x_to_pmu.spr_num <= ex1.pmu_spr_num;
|
||||
x_to_pmu.spr_val <= ex1.e.write_data;
|
||||
x_to_pmu.run <= '1';
|
||||
x_to_pmu.run <= ctrl.run;
|
||||
|
||||
-- XER forwarding. The CA and CA32 bits are only modified by instructions
|
||||
-- that are handled here, so for them we can just use the result most
|
||||
@@ -501,7 +578,7 @@ begin
|
||||
|
||||
-- N.B. the busy signal from each source includes the
|
||||
-- stage2 stall from that source in it.
|
||||
busy_out <= l_in.busy or ex1.busy or fp_in.busy;
|
||||
busy_out <= l_in.busy or ex1.busy or fp_in.busy or ctrl.wait_state;
|
||||
|
||||
valid_in <= e_in.valid and not (busy_out or flush_in or ex1.e.redirect or ex1.e.interrupt);
|
||||
|
||||
@@ -533,7 +610,13 @@ begin
|
||||
even_wr_enab := (ex1.se.ramspr_write_even and doit) or interrupt_in.intr;
|
||||
odd_wr_enab := (ex1.se.ramspr_write_odd and doit) or interrupt_in.intr;
|
||||
if interrupt_in.intr = '1' then
|
||||
wr_addr := RAMSPR_SRR0;
|
||||
if interrupt_in.hv_intr = '1' then
|
||||
wr_addr := RAMSPR_HSRR0;
|
||||
elsif interrupt_in.scv_int = '1' then
|
||||
wr_addr := RAMSPR_LR;
|
||||
else
|
||||
wr_addr := RAMSPR_SRR0;
|
||||
end if;
|
||||
else
|
||||
wr_addr := ex1.ramspr_wraddr;
|
||||
end if;
|
||||
@@ -573,6 +656,9 @@ begin
|
||||
else
|
||||
ramspr_result <= ramspr_odd;
|
||||
end if;
|
||||
if e_in.ramspr_32bit = '1' then
|
||||
ramspr_result(63 downto 32) <= 32x"0";
|
||||
end if;
|
||||
end process;
|
||||
|
||||
ramspr_write: process(clk)
|
||||
@@ -599,7 +685,7 @@ begin
|
||||
adder_result when "000",
|
||||
logical_result when "001",
|
||||
rotator_result when "010",
|
||||
muldiv_result when "100",
|
||||
multicyc_result when "100",
|
||||
ramspr_result when "101",
|
||||
misc_result when others;
|
||||
|
||||
@@ -610,16 +696,18 @@ begin
|
||||
ex1 <= reg_stage1_type_init;
|
||||
ex2 <= reg_stage2_type_init;
|
||||
ctrl <= ctrl_t_init;
|
||||
ctrl.msr <= (MSR_SF => '1', MSR_LE => '1', others => '0');
|
||||
ex1.msr <= (MSR_SF => '1', MSR_LE => '1', others => '0');
|
||||
ctrl.msr <= (MSR_SF => '1', MSR_HV => '1', MSR_LE => '1', others => '0');
|
||||
ex1.msr <= (MSR_SF => '1', MSR_HV => '1', MSR_LE => '1', others => '0');
|
||||
else
|
||||
ex1 <= ex1in;
|
||||
ex2 <= ex2in;
|
||||
ctrl <= ctrl_tmp;
|
||||
if valid_in = '1' then
|
||||
report "execute " & to_hstring(e_in.nia) & " op=" & insn_type_t'image(e_in.insn_type) &
|
||||
report "CPU " & natural'image(CPU_INDEX) & " execute " & to_hstring(e_in.nia) &
|
||||
" op=" & insn_type_t'image(e_in.insn_type) &
|
||||
" wr=" & to_hstring(ex1in.e.write_reg) & " we=" & std_ulogic'image(ex1in.e.write_enable) &
|
||||
" tag=" & integer'image(ex1in.e.instr_tag.tag) & std_ulogic'image(ex1in.e.instr_tag.valid);
|
||||
" tag=" & integer'image(ex1in.e.instr_tag.tag) & std_ulogic'image(ex1in.e.instr_tag.valid) &
|
||||
" 2nd=" & std_ulogic'image(e_in.second);
|
||||
end if;
|
||||
-- We mustn't get stalled on a cycle where execute2 is
|
||||
-- completing an instruction or generating an interrupt
|
||||
@@ -638,7 +726,18 @@ begin
|
||||
if dbg_spr_addr(7) = '1' then
|
||||
dbg_spr_data <= ramspr_result;
|
||||
else
|
||||
dbg_spr_data <= assemble_xer(xerc_in, ctrl.xer_low);
|
||||
case dbg_spr_addr(3 downto 0) is
|
||||
when SPRSEL_FSCR =>
|
||||
dbg_spr_data <= assemble_fscr(ctrl);
|
||||
when SPRSEL_HFSCR =>
|
||||
dbg_spr_data <= assemble_hfscr(ctrl);
|
||||
when SPRSEL_HEIR =>
|
||||
dbg_spr_data <= ctrl.heir;
|
||||
when SPRSEL_CFAR =>
|
||||
dbg_spr_data <= ctrl.cfar;
|
||||
when others =>
|
||||
dbg_spr_data <= assemble_xer(xerc_in, ctrl.xer_low);
|
||||
end case;
|
||||
end if;
|
||||
dbg_spr_ack <= '1';
|
||||
end if;
|
||||
@@ -769,17 +868,21 @@ begin
|
||||
x_to_mult_32s.subtract <= '0';
|
||||
x_to_mult_32s.addend <= (others => '0');
|
||||
|
||||
case ex1.mul_select is
|
||||
when "00" =>
|
||||
muldiv_result <= multiply_to_x.result(63 downto 0);
|
||||
when "01" =>
|
||||
muldiv_result <= multiply_to_x.result(127 downto 64);
|
||||
when "10" =>
|
||||
muldiv_result <= multiply_to_x.result(63 downto 32) &
|
||||
multiply_to_x.result(63 downto 32);
|
||||
when others =>
|
||||
muldiv_result <= divider_to_x.write_reg_data;
|
||||
end case;
|
||||
if ex1.mul_select(2) = '0' then
|
||||
case ex1.mul_select(1 downto 0) is
|
||||
when "00" =>
|
||||
multicyc_result <= multiply_to_x.result(63 downto 0);
|
||||
when "01" =>
|
||||
multicyc_result <= multiply_to_x.result(63 downto 32) &
|
||||
multiply_to_x.result(63 downto 32);
|
||||
when others =>
|
||||
multicyc_result <= multiply_to_x.result(127 downto 64);
|
||||
end case;
|
||||
elsif ex1.mul_select(0) = '1' and not HAS_FPU then
|
||||
multicyc_result <= divider_to_x.write_reg_data;
|
||||
else
|
||||
multicyc_result <= bsort_result;
|
||||
end if;
|
||||
|
||||
-- Compute misc_result
|
||||
case e_in.sub_select is
|
||||
@@ -1047,7 +1150,7 @@ begin
|
||||
slow_op := '0';
|
||||
owait := '0';
|
||||
|
||||
if e_in.illegal_suffix = '1' then
|
||||
if e_in.illegal_suffix = '1' or e_in.illegal_form = '1' then
|
||||
illegal := '1';
|
||||
elsif ex1.msr(MSR_PR) = '1' and instr_is_privileged(e_in.insn_type, e_in.insn) then
|
||||
privileged := '1';
|
||||
@@ -1058,18 +1161,20 @@ begin
|
||||
when OP_ILLEGAL =>
|
||||
illegal := '1';
|
||||
when OP_SC =>
|
||||
-- check bit 1 of the instruction is 1 so we know this is sc;
|
||||
-- 0 would mean scv, so generate an illegal instruction interrupt
|
||||
-- check bit 1 of the instruction to distinguish sc from scv
|
||||
if e_in.insn(1) = '1' then
|
||||
v.trap := '1';
|
||||
v.advance_nia := '1';
|
||||
-- sc
|
||||
v.e.intr_vec := 16#C00#;
|
||||
if e_in.valid = '1' then
|
||||
report "sc";
|
||||
end if;
|
||||
else
|
||||
illegal := '1';
|
||||
-- scv
|
||||
v.se.scv_trap := '1';
|
||||
v.e.intr_vec := to_integer(unsigned(e_in.insn(11 downto 5))) * 32;
|
||||
end if;
|
||||
v.trap := '1';
|
||||
v.advance_nia := '1';
|
||||
when OP_ATTN =>
|
||||
-- check bits 1-10 of the instruction to make sure it's attn
|
||||
-- if not then it is illegal
|
||||
@@ -1081,8 +1186,8 @@ begin
|
||||
else
|
||||
illegal := '1';
|
||||
end if;
|
||||
when OP_NOP | OP_DCBF | OP_DCBST | OP_DCBT | OP_DCBTST | OP_ICBT =>
|
||||
-- Do nothing
|
||||
when OP_NOP | OP_DCBST | OP_ICBT =>
|
||||
-- Do nothing
|
||||
when OP_ADD =>
|
||||
if e_in.output_carry = '1' then
|
||||
if e_in.input_carry /= OV then
|
||||
@@ -1126,7 +1231,7 @@ begin
|
||||
if ex1.msr(MSR_BE) = '1' then
|
||||
v.do_trace := '1';
|
||||
end if;
|
||||
v.se.write_cfar := '1';
|
||||
v.se.set_cfar := '1';
|
||||
when OP_BC =>
|
||||
-- If CTR is being decremented, it is in ramspr_odd.
|
||||
bo := insn_bo(e_in.insn);
|
||||
@@ -1145,7 +1250,7 @@ begin
|
||||
if ex1.msr(MSR_BE) = '1' then
|
||||
v.do_trace := '1';
|
||||
end if;
|
||||
v.se.write_cfar := v.take_branch;
|
||||
v.se.set_cfar := v.take_branch;
|
||||
when OP_BCREG =>
|
||||
-- If CTR is being decremented, it is in ramspr_odd.
|
||||
-- The target address is in ramspr_result (LR, CTR or TAR).
|
||||
@@ -1158,15 +1263,20 @@ begin
|
||||
if ex1.msr(MSR_BE) = '1' then
|
||||
v.do_trace := '1';
|
||||
end if;
|
||||
v.se.write_cfar := v.take_branch;
|
||||
v.se.set_cfar := v.take_branch;
|
||||
|
||||
when OP_RFID =>
|
||||
-- rfid, hrfid and rfscv.
|
||||
-- These all act the same given that we don't have
|
||||
-- privileged non-hypervisor mode or ultravisor mode.
|
||||
srr1 := ramspr_odd;
|
||||
v.e.redir_mode := (srr1(MSR_IR) or srr1(MSR_PR)) & not srr1(MSR_PR) &
|
||||
not srr1(MSR_LE) & not srr1(MSR_SF);
|
||||
-- Can't use msr_copy here because the partial function MSR
|
||||
-- bits should be left unchanged, not zeroed.
|
||||
v.new_msr(63 downto 31) := srr1(63 downto 31);
|
||||
v.new_msr(63 downto 61) := srr1(63 downto 61);
|
||||
v.new_msr(MSR_HV) := '1';
|
||||
v.new_msr(59 downto 31) := srr1(59 downto 31);
|
||||
v.new_msr(26 downto 22) := srr1(26 downto 22);
|
||||
v.new_msr(15 downto 0) := srr1(15 downto 0);
|
||||
if srr1(MSR_PR) = '1' then
|
||||
@@ -1176,14 +1286,14 @@ begin
|
||||
end if;
|
||||
v.se.write_msr := '1';
|
||||
v.e.redirect := '1';
|
||||
v.se.write_cfar := '1';
|
||||
v.se.set_cfar := '1';
|
||||
if HAS_FPU then
|
||||
v.fp_intr := fp_in.exception and
|
||||
(srr1(MSR_FE0) or srr1(MSR_FE1));
|
||||
end if;
|
||||
v.do_trace := '0';
|
||||
|
||||
when OP_CNTZ | OP_POPCNT =>
|
||||
when OP_COUNTB =>
|
||||
v.res2_sel := "01";
|
||||
slow_op := '1';
|
||||
when OP_ISEL =>
|
||||
@@ -1270,6 +1380,18 @@ begin
|
||||
v.se.write_dec := '1';
|
||||
when SPRSEL_LOGA =>
|
||||
v.se.write_loga := '1';
|
||||
when SPRSEL_CFAR =>
|
||||
v.se.write_cfar := '1';
|
||||
when SPRSEL_FSCR =>
|
||||
v.se.write_fscr := '1';
|
||||
when SPRSEL_HFSCR =>
|
||||
v.se.write_hfscr := '1';
|
||||
when SPRSEL_HEIR =>
|
||||
v.se.write_heir := '1';
|
||||
when SPRSEL_CTRL =>
|
||||
v.se.write_ctrl := '1';
|
||||
when SPRSEL_DSCR =>
|
||||
v.se.write_dscr := '1';
|
||||
when others =>
|
||||
end case;
|
||||
end if;
|
||||
@@ -1293,6 +1415,11 @@ begin
|
||||
when OP_ICBI =>
|
||||
v.se.icache_inval := '1';
|
||||
|
||||
when OP_BSORT =>
|
||||
v.start_bsort := '1';
|
||||
slow_op := '1';
|
||||
owait := '1';
|
||||
|
||||
when OP_MUL_L64 =>
|
||||
if e_in.is_32bit = '1' then
|
||||
v.se.mult_32s := '1';
|
||||
@@ -1321,6 +1448,11 @@ begin
|
||||
owait := '1';
|
||||
end if;
|
||||
|
||||
when OP_WAIT =>
|
||||
if e_in.insn(22 downto 21) = "00" then
|
||||
v.se.enter_wait := '1';
|
||||
end if;
|
||||
|
||||
when OP_FETCH_FAILED =>
|
||||
-- Handling an ITLB miss doesn't count as having executed an instruction
|
||||
v.do_trace := '0';
|
||||
@@ -1331,7 +1463,25 @@ begin
|
||||
end if;
|
||||
end case;
|
||||
|
||||
if misaligned = '1' then
|
||||
if ex1.msr(MSR_PR) = '1' and e_in.prefixed = '1' and
|
||||
(ctrl.hfscr_pref = '0' or ctrl.fscr_pref = '0') then
|
||||
-- [Hypervisor] facility unavailable for prefixed instructions,
|
||||
-- which has higher priority than the alignment interrupt for
|
||||
-- misaligned prefixed instructions, which has higher priority than
|
||||
-- other [hypervisor] facility unavailable interrupts (e.g. for
|
||||
-- plfs with HFSCR[FP] = 0).
|
||||
v.exception := '1';
|
||||
v.ic := x"b";
|
||||
if ctrl.hfscr_pref = '0' then
|
||||
v.e.hv_intr := '1';
|
||||
v.e.intr_vec := 16#f80#;
|
||||
v.se.write_hic := '1';
|
||||
else
|
||||
v.e.intr_vec := 16#f60#;
|
||||
v.se.write_ic := '1';
|
||||
end if;
|
||||
|
||||
elsif misaligned = '1' then
|
||||
-- generate an alignment interrupt
|
||||
-- This is higher priority than illegal because a misaligned
|
||||
-- prefix will come down as an OP_ILLEGAL instruction.
|
||||
@@ -1354,15 +1504,62 @@ begin
|
||||
end if;
|
||||
|
||||
elsif illegal = '1' then
|
||||
-- generate hypervisor emulation assistance interrupt (HEAI)
|
||||
-- and write the offending instruction into HEIR
|
||||
v.exception := '1';
|
||||
v.e.srr1(47 - 34) := e_in.prefixed;
|
||||
-- Since we aren't doing Hypervisor emulation assist (0xe40) we
|
||||
-- set bit 44 to indicate we have an illegal
|
||||
v.e.srr1(47 - 44) := '1';
|
||||
v.e.intr_vec := 16#e40#;
|
||||
v.e.hv_intr := '1';
|
||||
v.se.set_heir := '1';
|
||||
if e_in.valid = '1' then
|
||||
report "illegal instruction";
|
||||
end if;
|
||||
|
||||
elsif ex1.msr(MSR_PR) = '1' and v.se.scv_trap = '1' and
|
||||
ctrl.fscr_scv = '0' then
|
||||
-- Facility unavailable for scv instruction
|
||||
v.exception := '1';
|
||||
v.ic := x"c";
|
||||
v.e.intr_vec := 16#f60#;
|
||||
v.se.write_ic := '1';
|
||||
|
||||
elsif ex1.msr(MSR_PR) = '1' and e_in.uses_tar = '1' and
|
||||
(ctrl.hfscr_tar = '0' or ctrl.fscr_tar = '0') then
|
||||
-- [Hypervisor] facility unavailable for TAR access
|
||||
v.exception := '1';
|
||||
v.ic := x"8";
|
||||
if ctrl.hfscr_tar = '0' then
|
||||
v.e.hv_intr := '1';
|
||||
v.e.intr_vec := 16#f80#;
|
||||
v.se.write_hic := '1';
|
||||
else
|
||||
v.e.intr_vec := 16#f60#;
|
||||
v.se.write_ic := '1';
|
||||
end if;
|
||||
|
||||
elsif ex1.msr(MSR_PR) = '1' and e_in.uses_dscr = '1' and
|
||||
(ctrl.hfscr_dscr = '0' or ctrl.fscr_dscr = '0') then
|
||||
-- [Hypervisor] facility unavailable for DSCR access
|
||||
v.exception := '1';
|
||||
v.ic := x"2";
|
||||
if ctrl.hfscr_dscr = '0' then
|
||||
v.e.hv_intr := '1';
|
||||
v.e.intr_vec := 16#f80#;
|
||||
v.se.write_hic := '1';
|
||||
else
|
||||
v.e.intr_vec := 16#f60#;
|
||||
v.se.write_ic := '1';
|
||||
end if;
|
||||
|
||||
elsif HAS_FPU and ex1.msr(MSR_PR) = '1' and e_in.fac = FPU and
|
||||
ctrl.hfscr_fp = '0' then
|
||||
-- Hypervisor facility unavailable for FP instructions
|
||||
v.exception := '1';
|
||||
v.ic := x"0";
|
||||
v.e.hv_intr := '1';
|
||||
v.e.intr_vec := 16#f80#;
|
||||
v.se.write_hic := '1';
|
||||
|
||||
elsif HAS_FPU and ex1.msr(MSR_FP) = '0' and e_in.fac = FPU then
|
||||
-- generate a floating-point unavailable interrupt
|
||||
v.exception := '1';
|
||||
@@ -1391,19 +1588,24 @@ begin
|
||||
variable fv : Execute1ToFPUType;
|
||||
variable go : std_ulogic;
|
||||
variable bypass_valid : std_ulogic;
|
||||
variable is_scv : std_ulogic;
|
||||
begin
|
||||
v := ex1;
|
||||
if (ex1.busy or l_in.busy or fp_in.busy) = '0' then
|
||||
if busy_out = '0' then
|
||||
v.e := actions.e;
|
||||
v.e.valid := '0';
|
||||
v.oe := e_in.oe;
|
||||
v.spr_select := e_in.spr_select;
|
||||
v.pmu_spr_num := e_in.insn(20 downto 16);
|
||||
v.mul_select := e_in.sub_select(1 downto 0);
|
||||
v.mul_select := e_in.sub_select;
|
||||
v.se := side_effect_init;
|
||||
v.ramspr_wraddr := e_in.ramspr_wraddr;
|
||||
v.lr_from_next := e_in.lr;
|
||||
v.ramspr_odd_data := actions.ramspr_odd_data;
|
||||
v.ic := actions.ic;
|
||||
v.prefixed := e_in.prefixed;
|
||||
v.insn := e_in.insn;
|
||||
v.prefix := e_in.prefix;
|
||||
end if;
|
||||
|
||||
lv := Execute1ToLoadstore1Init;
|
||||
@@ -1426,7 +1628,7 @@ begin
|
||||
rot_clear_right <= '1' when e_in.insn_type = OP_RLC or e_in.insn_type = OP_RLCR else '0';
|
||||
rot_sign_ext <= '1' when e_in.insn_type = OP_EXTSWSLI else '0';
|
||||
|
||||
do_popcnt <= '1' when e_in.insn_type = OP_POPCNT else '0';
|
||||
do_popcnt <= '1' when e_in.insn_type = OP_COUNTB and e_in.insn(7 downto 6) = "11" else '0';
|
||||
|
||||
if valid_in = '1' then
|
||||
v.prev_op := e_in.insn_type;
|
||||
@@ -1454,10 +1656,9 @@ begin
|
||||
v.e.srr1(47 - 33) := '1';
|
||||
v.e.srr1(47 - 34) := ex1.prev_prefixed;
|
||||
if ex1.prev_op = OP_LOAD or ex1.prev_op = OP_ICBI or ex1.prev_op = OP_ICBT or
|
||||
ex1.prev_op = OP_DCBT or ex1.prev_op = OP_DCBST or ex1.prev_op = OP_DCBF then
|
||||
ex1.prev_op = OP_DCBF then
|
||||
v.e.srr1(47 - 35) := '1';
|
||||
elsif ex1.prev_op = OP_STORE or ex1.prev_op = OP_DCBZ or
|
||||
ex1.prev_op = OP_DCBTST then
|
||||
elsif ex1.prev_op = OP_STORE or ex1.prev_op = OP_DCBZ then
|
||||
v.e.srr1(47 - 36) := '1';
|
||||
end if;
|
||||
|
||||
@@ -1474,6 +1675,7 @@ begin
|
||||
v.e.intr_vec := 16#500#;
|
||||
report "IRQ valid: External";
|
||||
v.ext_interrupt := '1';
|
||||
v.e.hv_intr := '1';
|
||||
end if;
|
||||
v.e.srr1 := (others => '0');
|
||||
exception := '1';
|
||||
@@ -1500,6 +1702,7 @@ begin
|
||||
v.mul_in_progress := actions.start_mul;
|
||||
x_to_divider.valid <= actions.start_div;
|
||||
v.div_in_progress := actions.start_div;
|
||||
v.bsort_in_progress := actions.start_bsort;
|
||||
v.br_mispredict := v.e.redirect and actions.direct_branch;
|
||||
v.advance_nia := actions.advance_nia;
|
||||
v.redir_to_next := actions.redir_to_next;
|
||||
@@ -1510,7 +1713,7 @@ begin
|
||||
-- multiply is happening in order to stop following
|
||||
-- instructions from using the wrong XER value
|
||||
-- (and for simplicity in the OE=0 case).
|
||||
v.busy := actions.start_div or actions.start_mul;
|
||||
v.busy := actions.start_div or actions.start_mul or actions.start_bsort;
|
||||
|
||||
-- instruction for other units, i.e. LDST
|
||||
if e_in.unit = LDST then
|
||||
@@ -1520,6 +1723,8 @@ begin
|
||||
fv.valid := '1';
|
||||
end if;
|
||||
end if;
|
||||
is_scv := go and actions.se.scv_trap;
|
||||
bsort_start <= go and actions.start_bsort;
|
||||
|
||||
if not HAS_FPU and ex1.div_in_progress = '1' then
|
||||
v.div_in_progress := not divider_to_x.valid;
|
||||
@@ -1552,6 +1757,13 @@ begin
|
||||
end if;
|
||||
v.e.valid := '1';
|
||||
end if;
|
||||
if ex1.bsort_in_progress = '1' then
|
||||
v.bsort_in_progress := not bsort_done;
|
||||
v.e.valid := bsort_done;
|
||||
v.busy := not bsort_done;
|
||||
v.e.write_data := alu_result;
|
||||
bypass_valid := bsort_done;
|
||||
end if;
|
||||
|
||||
if v.e.write_xerc_enable = '1' and v.e.valid = '1' then
|
||||
v.xerc := v.e.xerc;
|
||||
@@ -1560,6 +1772,7 @@ begin
|
||||
|
||||
if (ex1.busy or l_in.busy or fp_in.busy) = '0' then
|
||||
v.e.interrupt := exception;
|
||||
v.e.is_scv := is_scv;
|
||||
end if;
|
||||
if v.e.valid = '0' then
|
||||
v.e.redirect := '0';
|
||||
@@ -1658,6 +1871,12 @@ begin
|
||||
log_wr_addr & ex2.log_addr_spr when SPRSEL_LOGA,
|
||||
log_rd_data when SPRSEL_LOGD,
|
||||
ctrl.cfar when SPRSEL_CFAR,
|
||||
assemble_fscr(ctrl) when SPRSEL_FSCR,
|
||||
assemble_hfscr(ctrl) when SPRSEL_HFSCR,
|
||||
ctrl.heir when SPRSEL_HEIR,
|
||||
assemble_ctrl(ctrl, ex1.msr(MSR_PR)) when SPRSEL_CTRL,
|
||||
39x"0" & ctrl.dscr when SPRSEL_DSCR,
|
||||
56x"0" & std_ulogic_vector(to_unsigned(CPU_INDEX, 8)) when SPRSEL_PIR,
|
||||
assemble_xer(ex1.e.xerc, ctrl.xer_low) when others;
|
||||
|
||||
stage2_stall <= l_in.l2stall or fp_in.f2stall;
|
||||
@@ -1673,6 +1892,7 @@ begin
|
||||
variable cr_mask : std_ulogic_vector(7 downto 0);
|
||||
variable sign, zero : std_ulogic;
|
||||
variable rcnz_hi, rcnz_lo : std_ulogic;
|
||||
variable irq_exc : std_ulogic;
|
||||
begin
|
||||
-- Next insn adder used in a couple of places
|
||||
next_nia <= std_ulogic_vector(unsigned(ex1.e.last_nia) + 4);
|
||||
@@ -1792,6 +2012,8 @@ begin
|
||||
ctrl_tmp.dec <= ex1.e.write_data;
|
||||
end if;
|
||||
if ex1.se.write_cfar = '1' then
|
||||
ctrl_tmp.cfar <= ex1.e.write_data;
|
||||
elsif ex1.se.set_cfar = '1' then
|
||||
ctrl_tmp.cfar <= ex1.e.last_nia;
|
||||
end if;
|
||||
if ex1.se.write_loga = '1' then
|
||||
@@ -1800,11 +2022,56 @@ begin
|
||||
v.log_addr_spr := std_ulogic_vector(unsigned(ex2.log_addr_spr) + 1);
|
||||
end if;
|
||||
x_to_pmu.mtspr <= ex1.se.write_pmuspr;
|
||||
if ex1.se.write_hfscr = '1' then
|
||||
ctrl_tmp.hfscr_ic <= ex1.e.write_data(59 downto 56);
|
||||
ctrl_tmp.hfscr_pref <= ex1.e.write_data(HFSCR_PREFIX);
|
||||
ctrl_tmp.hfscr_tar <= ex1.e.write_data(HFSCR_TAR);
|
||||
ctrl_tmp.hfscr_dscr <= ex1.e.write_data(HFSCR_DSCR);
|
||||
ctrl_tmp.hfscr_fp <= ex1.e.write_data(HFSCR_FP);
|
||||
elsif ex1.se.write_hic = '1' then
|
||||
ctrl_tmp.hfscr_ic <= ex1.ic;
|
||||
end if;
|
||||
if ex1.se.write_fscr = '1' then
|
||||
ctrl_tmp.fscr_ic <= ex1.e.write_data(59 downto 56);
|
||||
ctrl_tmp.fscr_pref <= ex1.e.write_data(FSCR_PREFIX);
|
||||
ctrl_tmp.fscr_scv <= ex1.e.write_data(FSCR_SCV);
|
||||
ctrl_tmp.fscr_tar <= ex1.e.write_data(FSCR_TAR);
|
||||
ctrl_tmp.fscr_dscr <= ex1.e.write_data(FSCR_DSCR);
|
||||
elsif ex1.se.write_ic = '1' then
|
||||
ctrl_tmp.fscr_ic <= ex1.ic;
|
||||
end if;
|
||||
if ex1.se.write_heir = '1' then
|
||||
ctrl_tmp.heir <= ex1.e.write_data;
|
||||
elsif ex1.se.set_heir = '1' then
|
||||
ctrl_tmp.heir(31 downto 0) <= ex1.insn;
|
||||
if ex1.prefixed = '1' then
|
||||
ctrl_tmp.heir(63 downto 58) <= 6x"01";
|
||||
ctrl_tmp.heir(57 downto 32) <= ex1.prefix;
|
||||
else
|
||||
ctrl_tmp.heir(63 downto 32) <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
if ex1.se.write_ctrl = '1' then
|
||||
ctrl_tmp.run <= ex1.e.write_data(0);
|
||||
end if;
|
||||
if ex1.se.write_dscr = '1' then
|
||||
ctrl_tmp.dscr <= ex1.e.write_data(24 downto 0);
|
||||
end if;
|
||||
if ex1.se.enter_wait = '1' then
|
||||
ctrl_tmp.wait_state <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- pending exceptions clear any wait state
|
||||
-- ex1.fp_exception_next is not tested because it is not possible to
|
||||
-- get into wait state with a pending FP exception.
|
||||
irq_exc := pmu_to_x.intr or ctrl.dec(63) or ext_irq_in;
|
||||
if ex1.trace_next = '1' or irq_exc = '1' or interrupt_in.intr = '1' then
|
||||
ctrl_tmp.wait_state <= '0';
|
||||
end if;
|
||||
|
||||
if interrupt_in.intr = '1' then
|
||||
ctrl_tmp.msr(MSR_SF) <= '1';
|
||||
ctrl_tmp.msr(MSR_EE) <= '0';
|
||||
ctrl_tmp.msr(MSR_PR) <= '0';
|
||||
ctrl_tmp.msr(MSR_SE) <= '0';
|
||||
ctrl_tmp.msr(MSR_BE) <= '0';
|
||||
@@ -1813,8 +2080,11 @@ begin
|
||||
ctrl_tmp.msr(MSR_FE1) <= '0';
|
||||
ctrl_tmp.msr(MSR_IR) <= '0';
|
||||
ctrl_tmp.msr(MSR_DR) <= '0';
|
||||
ctrl_tmp.msr(MSR_RI) <= '0';
|
||||
ctrl_tmp.msr(MSR_LE) <= '1';
|
||||
if interrupt_in.scv_int = '0' then
|
||||
ctrl_tmp.msr(MSR_EE) <= '0';
|
||||
ctrl_tmp.msr(MSR_RI) <= '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
bypass_valid := ex1.e.valid;
|
||||
@@ -1838,6 +2108,7 @@ begin
|
||||
e_out <= ex2.e;
|
||||
e_out.msr <= msr_copy(ctrl.msr);
|
||||
|
||||
run_out <= ctrl.run;
|
||||
terminate_out <= ex2.se.terminate;
|
||||
icache_inval <= ex2.se.icache_inval;
|
||||
|
||||
|
||||
@@ -391,7 +391,7 @@ begin
|
||||
v_int.next_nia := RESET_ADDRESS;
|
||||
end if;
|
||||
elsif w_in.interrupt = '1' then
|
||||
v_int.next_nia := 52x"0" & w_in.intr_vec(11 downto 2) & "00";
|
||||
v_int.next_nia := 47x"0" & w_in.intr_vec(16 downto 2) & "00";
|
||||
end if;
|
||||
if rst /= '0' or w_in.interrupt = '1' then
|
||||
v.req := '0';
|
||||
|
||||
@@ -142,6 +142,9 @@ end entity toplevel;
|
||||
|
||||
architecture behaviour of toplevel is
|
||||
|
||||
-- Status
|
||||
signal run_out : std_ulogic;
|
||||
|
||||
-- Reset signals:
|
||||
signal soc_rst : std_ulogic;
|
||||
signal pll_rst : std_ulogic;
|
||||
@@ -263,6 +266,7 @@ begin
|
||||
system_clk => system_clk,
|
||||
rst => soc_rst,
|
||||
sw_soc_reset => sw_rst,
|
||||
run_out => run_out,
|
||||
|
||||
-- UART signals
|
||||
uart0_txd => uart_main_tx,
|
||||
@@ -742,6 +746,7 @@ begin
|
||||
led4 <= system_clk_locked;
|
||||
led5 <= eth_clk_locked;
|
||||
led6 <= not soc_rst;
|
||||
led7 <= run_out;
|
||||
|
||||
-- GPIO
|
||||
gpio_in(10) <= btn0;
|
||||
|
||||
@@ -61,6 +61,9 @@ architecture behave of loadstore1 is
|
||||
dc_req : std_ulogic;
|
||||
load : std_ulogic;
|
||||
store : std_ulogic;
|
||||
flush : std_ulogic;
|
||||
touch : std_ulogic;
|
||||
sync : std_ulogic;
|
||||
tlbie : std_ulogic;
|
||||
dcbz : std_ulogic;
|
||||
read_spr : std_ulogic;
|
||||
@@ -84,6 +87,9 @@ architecture behave of loadstore1 is
|
||||
update : std_ulogic;
|
||||
xerc : xer_common_t;
|
||||
reserve : std_ulogic;
|
||||
atomic_qw : std_ulogic;
|
||||
atomic_first : std_ulogic;
|
||||
atomic_last : std_ulogic;
|
||||
rc : std_ulogic;
|
||||
nc : std_ulogic; -- non-cacheable access
|
||||
virt_mode : std_ulogic;
|
||||
@@ -97,7 +103,8 @@ architecture behave of loadstore1 is
|
||||
two_dwords : std_ulogic;
|
||||
incomplete : std_ulogic;
|
||||
end record;
|
||||
constant request_init : request_t := (valid => '0', dc_req => '0', load => '0', store => '0', tlbie => '0',
|
||||
constant request_init : request_t := (valid => '0', dc_req => '0', load => '0', store => '0',
|
||||
flush => '0', touch => '0', sync => '0', tlbie => '0',
|
||||
dcbz => '0', read_spr => '0', write_spr => '0', mmu_op => '0',
|
||||
instr_fault => '0', do_update => '0',
|
||||
mode_32bit => '0', prefixed => '0',
|
||||
@@ -108,6 +115,7 @@ architecture behave of loadstore1 is
|
||||
elt_length => x"0", byte_reverse => '0', brev_mask => "000",
|
||||
sign_extend => '0', update => '0',
|
||||
xerc => xerc_init, reserve => '0',
|
||||
atomic_qw => '0', atomic_first => '0', atomic_last => '0',
|
||||
rc => '0', nc => '0',
|
||||
virt_mode => '0', priv_mode => '0', load_sp => '0',
|
||||
sprsel => "00", ric => "00", is_slbia => '0', align_intr => '0',
|
||||
@@ -447,7 +455,10 @@ begin
|
||||
if l_in.second = '1' then
|
||||
-- for an update-form load, use the previous address
|
||||
-- as the value to write back to RA.
|
||||
addr := r1.addr0;
|
||||
-- for a quadword load or store, use with the previous
|
||||
-- address + 8.
|
||||
addr := std_ulogic_vector(unsigned(r1.addr0(63 downto 3)) + not l_in.update) &
|
||||
r1.addr0(2 downto 0);
|
||||
end if;
|
||||
if l_in.mode_32bit = '1' then
|
||||
addr(63 downto 32) := (others => '0');
|
||||
@@ -463,7 +474,7 @@ begin
|
||||
addr_mask := std_ulogic_vector(unsigned(l_in.length(2 downto 0)) - 1);
|
||||
|
||||
-- Do length_to_sel and work out if we are doing 2 dwords
|
||||
long_sel := xfer_data_sel(v.length, addr(2 downto 0));
|
||||
long_sel := xfer_data_sel(l_in.length, addr(2 downto 0));
|
||||
v.byte_sel := long_sel(7 downto 0);
|
||||
v.second_bytes := long_sel(15 downto 8);
|
||||
if long_sel(15 downto 8) /= "00000000" then
|
||||
@@ -472,23 +483,54 @@ begin
|
||||
|
||||
-- check alignment for larx/stcx
|
||||
misaligned := or (addr_mask and addr(2 downto 0));
|
||||
if l_in.repeat = '1' and l_in.update = '0' and addr(3) /= l_in.second then
|
||||
misaligned := '1';
|
||||
end if;
|
||||
v.align_intr := l_in.reserve and misaligned;
|
||||
|
||||
v.atomic_first := not misaligned and not l_in.second;
|
||||
v.atomic_last := not misaligned and (l_in.second or not l_in.repeat);
|
||||
|
||||
-- is this a quadword load or store? i.e. lq plq stq pstq lqarx stqcx.
|
||||
if l_in.repeat = '1' and l_in.update = '0' then
|
||||
if misaligned = '0' then
|
||||
-- Since the access is aligned we have to do it atomically
|
||||
v.atomic_qw := '1';
|
||||
else
|
||||
-- We require non-prefixed lq in LE mode to be aligned in order
|
||||
-- to avoid the case where RA = RT+1 and the second access faults
|
||||
-- after the first has overwritten RA.
|
||||
if l_in.op = OP_LOAD and l_in.byte_reverse = '0' and l_in.prefixed = '0' then
|
||||
v.align_intr := '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
case l_in.op is
|
||||
when OP_SYNC =>
|
||||
v.sync := '1';
|
||||
when OP_STORE =>
|
||||
v.store := '1';
|
||||
if l_in.length = "0000" then
|
||||
v.touch := '1';
|
||||
end if;
|
||||
when OP_LOAD =>
|
||||
-- Note: only RA updates have l_in.second = 1
|
||||
if l_in.second = '0' then
|
||||
if l_in.update = '0' or l_in.second = '0' then
|
||||
v.load := '1';
|
||||
if HAS_FPU and l_in.is_32bit = '1' then
|
||||
-- Allow an extra cycle for SP->DP precision conversion
|
||||
v.load_sp := '1';
|
||||
end if;
|
||||
if l_in.length = "0000" then
|
||||
v.touch := '1';
|
||||
end if;
|
||||
else
|
||||
-- write back address to RA
|
||||
v.do_update := '1';
|
||||
end if;
|
||||
when OP_DCBF =>
|
||||
v.load := '1';
|
||||
v.flush := '1';
|
||||
when OP_DCBZ =>
|
||||
v.dcbz := '1';
|
||||
v.align_intr := v.nc;
|
||||
@@ -508,13 +550,13 @@ begin
|
||||
v.mmu_op := '1';
|
||||
when others =>
|
||||
end case;
|
||||
v.dc_req := l_in.valid and (v.load or v.store or v.dcbz) and not v.align_intr;
|
||||
v.dc_req := l_in.valid and (v.load or v.store or v.sync or v.dcbz) and not v.align_intr;
|
||||
v.incomplete := v.dc_req and v.two_dwords;
|
||||
|
||||
-- Work out controls for load and store formatting
|
||||
brev_lenm1 := "000";
|
||||
if v.byte_reverse = '1' then
|
||||
brev_lenm1 := unsigned(v.length(2 downto 0)) - 1;
|
||||
brev_lenm1 := unsigned(l_in.length(2 downto 0)) - 1;
|
||||
end if;
|
||||
v.brev_mask := brev_lenm1;
|
||||
|
||||
@@ -699,7 +741,8 @@ begin
|
||||
end if;
|
||||
|
||||
interrupt := (r2.req.valid and r2.req.align_intr) or
|
||||
(d_in.error and d_in.cache_paradox) or m_in.err;
|
||||
(d_in.error and (d_in.cache_paradox or d_in.reserve_nc)) or
|
||||
m_in.err;
|
||||
if interrupt = '1' then
|
||||
v.req.valid := '0';
|
||||
v.busy := '0';
|
||||
@@ -855,7 +898,8 @@ begin
|
||||
|
||||
if d_in.valid = '1' then
|
||||
if r2.req.incomplete = '0' then
|
||||
write_enable := r2.req.load and not r2.req.load_sp;
|
||||
write_enable := r2.req.load and not r2.req.load_sp and
|
||||
not r2.req.flush and not r2.req.touch;
|
||||
-- stores write back rA update
|
||||
do_update := r2.req.update and r2.req.store;
|
||||
end if;
|
||||
@@ -865,6 +909,7 @@ begin
|
||||
-- signal an interrupt straight away
|
||||
exception := '1';
|
||||
dsisr(63 - 38) := not r2.req.load;
|
||||
dsisr(63 - 37) := d_in.reserve_nc;
|
||||
-- XXX there is no architected bit for this
|
||||
-- (probably should be a machine check in fact)
|
||||
dsisr(63 - 35) := d_in.cache_paradox;
|
||||
@@ -950,8 +995,14 @@ begin
|
||||
d_out.valid <= stage1_dcreq;
|
||||
d_out.load <= stage1_req.load;
|
||||
d_out.dcbz <= stage1_req.dcbz;
|
||||
d_out.flush <= stage1_req.flush;
|
||||
d_out.touch <= stage1_req.touch;
|
||||
d_out.sync <= stage1_req.sync;
|
||||
d_out.nc <= stage1_req.nc;
|
||||
d_out.reserve <= stage1_req.reserve;
|
||||
d_out.atomic_qw <= stage1_req.atomic_qw;
|
||||
d_out.atomic_first <= stage1_req.atomic_first;
|
||||
d_out.atomic_last <= stage1_req.atomic_last;
|
||||
d_out.addr <= stage1_req.addr;
|
||||
d_out.byte_sel <= stage1_req.byte_sel;
|
||||
d_out.virt_mode <= stage1_req.virt_mode;
|
||||
@@ -960,8 +1011,14 @@ begin
|
||||
d_out.valid <= req;
|
||||
d_out.load <= r2.req.load;
|
||||
d_out.dcbz <= r2.req.dcbz;
|
||||
d_out.flush <= r2.req.flush;
|
||||
d_out.touch <= r2.req.touch;
|
||||
d_out.sync <= r2.req.sync;
|
||||
d_out.nc <= r2.req.nc;
|
||||
d_out.reserve <= r2.req.reserve;
|
||||
d_out.atomic_qw <= r2.req.atomic_qw;
|
||||
d_out.atomic_first <= r2.req.atomic_first;
|
||||
d_out.atomic_last <= r2.req.atomic_last;
|
||||
d_out.addr <= r2.req.addr;
|
||||
d_out.byte_sel <= r2.req.byte_sel;
|
||||
d_out.virt_mode <= r2.req.virt_mode;
|
||||
|
||||
@@ -20,6 +20,7 @@ filesets:
|
||||
- sim_console.vhdl
|
||||
- logical.vhdl
|
||||
- countbits.vhdl
|
||||
- bitsort.vhdl
|
||||
- control.vhdl
|
||||
- execute1.vhdl
|
||||
- fpu.vhdl
|
||||
|
||||
@@ -121,6 +121,8 @@ architecture behaviour of predecoder is
|
||||
2#011110_01110# to 2#011110_01111# => INSN_rldimi,
|
||||
2#011110_10000# to 2#011110_10001# => INSN_rldcl,
|
||||
2#011110_10010# to 2#011110_10011# => INSN_rldcr,
|
||||
-- major opcode 56
|
||||
2#111000_00000# to 2#111000_11111# => INSN_lq,
|
||||
-- major opcode 58
|
||||
2#111010_00000# => INSN_ld,
|
||||
2#111010_00001# => INSN_ldu,
|
||||
@@ -161,20 +163,28 @@ architecture behaviour of predecoder is
|
||||
-- major opcode 62
|
||||
2#111110_00000# => INSN_std,
|
||||
2#111110_00001# => INSN_stdu,
|
||||
2#111110_00010# => INSN_stq,
|
||||
2#111110_00100# => INSN_std,
|
||||
2#111110_00101# => INSN_stdu,
|
||||
2#111110_00110# => INSN_stq,
|
||||
2#111110_01000# => INSN_std,
|
||||
2#111110_01001# => INSN_stdu,
|
||||
2#111110_01010# => INSN_stq,
|
||||
2#111110_01100# => INSN_std,
|
||||
2#111110_01101# => INSN_stdu,
|
||||
2#111110_01110# => INSN_stq,
|
||||
2#111110_10000# => INSN_std,
|
||||
2#111110_10001# => INSN_stdu,
|
||||
2#111110_10010# => INSN_stq,
|
||||
2#111110_10100# => INSN_std,
|
||||
2#111110_10101# => INSN_stdu,
|
||||
2#111110_10110# => INSN_stq,
|
||||
2#111110_11000# => INSN_std,
|
||||
2#111110_11001# => INSN_stdu,
|
||||
2#111110_11010# => INSN_stq,
|
||||
2#111110_11100# => INSN_std,
|
||||
2#111110_11101# => INSN_stdu,
|
||||
2#111110_11110# => INSN_stq,
|
||||
-- major opcode 63
|
||||
2#111111_00100# to 2#111111_00101# => INSN_fdiv,
|
||||
2#111111_01000# to 2#111111_01001# => INSN_fsub,
|
||||
@@ -190,8 +200,9 @@ architecture behaviour of predecoder is
|
||||
2#111111_11110# to 2#111111_11111# => INSN_fnmadd,
|
||||
-- prefix word, PO1
|
||||
2#000001_00000# to 2#000001_11111# => INSN_prefix,
|
||||
-- Major opcodes 57 and 61 are SFFS load/store instructions when prefixed
|
||||
-- Major opcodes 57, 60 and 61 are SFFS load/store instructions when prefixed
|
||||
2#111001_00000# to 2#111001_11111# => INSN_op57,
|
||||
2#111100_00000# to 2#111100_11111# => INSN_op60,
|
||||
2#111101_00000# to 2#111101_11111# => INSN_op61,
|
||||
others => INSN_illegal
|
||||
);
|
||||
@@ -219,6 +230,7 @@ architecture behaviour of predecoder is
|
||||
2#0_00101_11011# => INSN_brd,
|
||||
2#0_01001_11010# => INSN_cbcdtd,
|
||||
2#0_01000_11010# => INSN_cdtbcd,
|
||||
2#0_00110_11100# => INSN_cfuged,
|
||||
2#0_00000_00000# => INSN_cmp,
|
||||
2#0_01111_11100# => INSN_cmpb,
|
||||
2#0_00111_00000# => INSN_cmpeqb,
|
||||
@@ -316,6 +328,7 @@ architecture behaviour of predecoder is
|
||||
2#0_11001_10101# => INSN_lhzcix,
|
||||
2#0_01001_10111# => INSN_lhzux,
|
||||
2#0_01000_10111# => INSN_lhzx,
|
||||
2#0_01000_10100# => INSN_lqarx,
|
||||
2#0_00000_10100# => INSN_lwarx,
|
||||
2#0_01011_10101# => INSN_lwaux,
|
||||
2#0_01010_10101# => INSN_lwax,
|
||||
@@ -363,6 +376,8 @@ architecture behaviour of predecoder is
|
||||
2#0_00011_11100# => INSN_nor,
|
||||
2#0_01101_11100# => INSN_or,
|
||||
2#0_01100_11100# => INSN_orc,
|
||||
2#0_00100_11100# => INSN_pdepd,
|
||||
2#0_00101_11100# => INSN_pextd,
|
||||
2#0_00011_11010# => INSN_popcntb,
|
||||
2#0_01111_11010# => INSN_popcntd,
|
||||
2#0_01011_11010# => INSN_popcntw,
|
||||
@@ -402,6 +417,7 @@ architecture behaviour of predecoder is
|
||||
2#0_10110_10110# => INSN_sthcx,
|
||||
2#0_01101_10111# => INSN_sthux,
|
||||
2#0_01100_10111# => INSN_sthx,
|
||||
2#0_00101_10110# => INSN_stqcx,
|
||||
2#0_10100_10110# => INSN_stwbrx,
|
||||
2#0_11100_10101# => INSN_stwcix,
|
||||
2#0_00100_10110# => INSN_stwcx,
|
||||
@@ -447,6 +463,8 @@ architecture behaviour of predecoder is
|
||||
2#1_00100_11110# => INSN_isync,
|
||||
2#1_00000_10000# => INSN_mcrf,
|
||||
2#1_00000_11010# => INSN_rfid,
|
||||
2#1_00010_11010# => INSN_rfscv,
|
||||
2#1_01000_11010# => INSN_rfid, -- hrfid
|
||||
|
||||
-- Major opcode 59
|
||||
-- Address bits are 1, insn(10..6), 1, 0, insn(3..1)
|
||||
|
||||
@@ -87,13 +87,13 @@ const char *units[4] = { "al", "ls", "fp", "3?" };
|
||||
const char *ops[64] =
|
||||
{
|
||||
"illegal", "nop ", "add ", "attn ", "b ", "bc ", "bcreg ", "bcd ",
|
||||
"bperm ", "brev ", "cmp ", "cmpb ", "cmpeqb ", "cmprb ", "cntz ", "crop ",
|
||||
"darn ", "dcbf ", "dcbst ", "dcbt ", "dcbtst ", "dcbz ", "icbi ", "icbt ",
|
||||
"fpcmp ", "fparith", "fpmove ", "fpmisc ", "div ", "dive ", "mod ", "exts ",
|
||||
"extswsl", "isel ", "isync ", "logic ", "ld ", "st ", "mcrxrx ", "mfcr ",
|
||||
"mfmsr ", "mfspr ", "mtcrf ", "mtmsr ", "mtspr ", "mull64 ", "mulh64 ", "mulh32 ",
|
||||
"popcnt ", "prty ", "rfid ", "rlc ", "rlcl ", "rlcr ", "sc ", "setb ",
|
||||
"shl ", "shr ", "sync ", "tlbie ", "trap ", "xor ", "addg6s ", "ffail ",
|
||||
"bperm ", "brev ", "cmp ", "cmpb ", "cmpeqb ", "cmprb ", "countb ", "crop ",
|
||||
"darn ", "dcbf ", "dcbst ", "xcbt ", "dcbtst ", "dcbz ", "icbi ", "fpcmp ",
|
||||
"fparith", "fpmove ", "fpmisc ", "div ", "dive ", "mod ", "exts ", "extswsl",
|
||||
"isel ", "isync ", "logic ", "ld ", "st ", "mcrxrx ", "mfcr ", "mfmsr ",
|
||||
"mfspr ", "mtcrf ", "mtmsr ", "mtspr ", "mull64 ", "mulh64 ", "mulh32 ", "bsort ",
|
||||
"prty ", "rfid ", "rlc ", "rlcl ", "rlcr ", "sc ", "setb ", "shl ",
|
||||
"shr ", "sync ", "tlbie ", "trap ", "xor ", "addg6s ", "wait ", "ffail ",
|
||||
};
|
||||
|
||||
const char *spr_names[13] =
|
||||
|
||||
@@ -550,6 +550,7 @@ static const char *fast_spr_names[] =
|
||||
"lr", "ctr", "srr0", "srr1", "hsrr0", "hsrr1",
|
||||
"sprg0", "sprg1", "sprg2", "sprg3",
|
||||
"hsprg0", "hsprg1", "xer", "tar",
|
||||
"fscr", "hfscr", "heir", "cfar",
|
||||
};
|
||||
|
||||
static const char *ldst_spr_names[] = {
|
||||
|
||||
4
soc.vhdl
4
soc.vhdl
@@ -99,6 +99,8 @@ entity soc is
|
||||
rst : in std_ulogic;
|
||||
system_clk : in std_ulogic;
|
||||
|
||||
run_out : out std_ulogic;
|
||||
|
||||
-- "Large" (64-bit) DRAM wishbone
|
||||
wb_dram_in : out wishbone_master_out;
|
||||
wb_dram_out : in wishbone_slave_out := wishbone_slave_out_init;
|
||||
@@ -349,6 +351,7 @@ begin
|
||||
processor: entity work.core
|
||||
generic map(
|
||||
SIM => SIM,
|
||||
CPU_INDEX => 0,
|
||||
HAS_FPU => HAS_FPU,
|
||||
HAS_BTC => HAS_BTC,
|
||||
DISABLE_FLATTEN => DISABLE_FLATTEN_CORE,
|
||||
@@ -366,6 +369,7 @@ begin
|
||||
clk => system_clk,
|
||||
rst => rst_core,
|
||||
alt_reset => alt_reset_d,
|
||||
run_out => run_out,
|
||||
wishbone_insn_in => wishbone_icore_in,
|
||||
wishbone_insn_out => wishbone_icore_out,
|
||||
wishbone_data_in => wishbone_dcore_in,
|
||||
|
||||
@@ -74,25 +74,15 @@ ill_test_1:
|
||||
EXCEPTION(0x500)
|
||||
EXCEPTION(0x600)
|
||||
|
||||
// We shouldn't get a Program interrupt at 700, so fail
|
||||
. = 0x700
|
||||
mtsprg0 %r3
|
||||
mtsprg1 %r4
|
||||
|
||||
// test for bit 44 being set for ILL
|
||||
mfsrr1 %r3
|
||||
li %r4, 1
|
||||
sldi %r4, %r4, (63-44)
|
||||
and. %r4, %r4, %r3
|
||||
li %r4, 8 // PASS so skip 2 instructions
|
||||
bne 1f
|
||||
li %r4, 4 // FAIL so only skip 1 instruction. Return will catch
|
||||
1:
|
||||
mfsrr0 %r3
|
||||
add %r3, %r3, %r4 // skip some instructions
|
||||
addi %r3, %r3, 4 // skip one instruction, causing a fail
|
||||
mtsrr0 %r3
|
||||
|
||||
mfsprg0 %r3
|
||||
mfsprg1 %r4
|
||||
rfid
|
||||
|
||||
EXCEPTION(0x800)
|
||||
@@ -104,7 +94,18 @@ ill_test_1:
|
||||
EXCEPTION(0xd00)
|
||||
EXCEPTION(0xe00)
|
||||
EXCEPTION(0xe20)
|
||||
EXCEPTION(0xe40)
|
||||
|
||||
// We now expect a HEAI at e40 for illegal instructions
|
||||
. = 0xe40
|
||||
mthsprg0 %r3
|
||||
|
||||
mfhsrr0 %r3
|
||||
addi %r3, %r3, 8 // skip one instruction, causing success
|
||||
mthsrr0 %r3
|
||||
|
||||
mfhsprg0 %r3
|
||||
hrfid
|
||||
|
||||
EXCEPTION(0xe60)
|
||||
EXCEPTION(0xe80)
|
||||
EXCEPTION(0xf00)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define MSR_LE 0x1
|
||||
#define MSR_DR 0x10
|
||||
#define MSR_IR 0x20
|
||||
#define MSR_HV 0x1000000000000000ul
|
||||
#define MSR_SF 0x8000000000000000ul
|
||||
|
||||
extern int test_read(long *addr, long *ret, long init);
|
||||
@@ -450,11 +451,11 @@ int mmu_test_11(void)
|
||||
unsigned long ptr = 0x523000;
|
||||
|
||||
/* this should fail */
|
||||
if (test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* SRR0 and SRR1 should be set correctly */
|
||||
if (mfspr(SRR0) != (long) ptr ||
|
||||
mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE))
|
||||
mfspr(SRR1) != (MSR_SF | MSR_HV | 0x40000000 | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
@@ -468,12 +469,12 @@ int mmu_test_12(void)
|
||||
/* create PTE */
|
||||
map((void *)ptr, (void *)mem, PERM_EX | REF);
|
||||
/* this should succeed and be a cache miss */
|
||||
if (!test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* create a second PTE */
|
||||
map((void *)ptr2, (void *)mem, PERM_EX | REF);
|
||||
/* this should succeed and be a cache hit */
|
||||
if (!test_exec(0, ptr2, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (!test_exec(0, ptr2, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
@@ -487,18 +488,18 @@ int mmu_test_13(void)
|
||||
/* create a PTE */
|
||||
map((void *)ptr, (void *)mem, PERM_EX | REF);
|
||||
/* this should succeed */
|
||||
if (!test_exec(1, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (!test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* invalidate the PTE */
|
||||
unmap((void *)ptr);
|
||||
/* install a second PTE */
|
||||
map((void *)ptr2, (void *)mem, PERM_EX | REF);
|
||||
/* this should fail */
|
||||
if (test_exec(1, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
/* SRR0 and SRR1 should be set correctly */
|
||||
if (mfspr(SRR0) != (long) ptr ||
|
||||
mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE))
|
||||
mfspr(SRR1) != (MSR_SF | MSR_HV | 0x40000000 | MSR_IR | MSR_LE))
|
||||
return 3;
|
||||
return 0;
|
||||
}
|
||||
@@ -513,16 +514,16 @@ int mmu_test_14(void)
|
||||
/* create a PTE */
|
||||
map((void *)ptr, (void *)mem, PERM_EX | REF);
|
||||
/* this should fail due to second page not being mapped */
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* SRR0 and SRR1 should be set correctly */
|
||||
if (mfspr(SRR0) != ptr2 ||
|
||||
mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE))
|
||||
mfspr(SRR1) != (MSR_SF | MSR_HV | 0x40000000 | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
/* create a PTE for the second page */
|
||||
map((void *)ptr2, (void *)mem2, PERM_EX | REF);
|
||||
/* this should succeed */
|
||||
if (!test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 3;
|
||||
return 0;
|
||||
}
|
||||
@@ -535,11 +536,11 @@ int mmu_test_15(void)
|
||||
/* create a PTE without execute permission */
|
||||
map((void *)ptr, (void *)mem, DFLT_PERM);
|
||||
/* this should fail */
|
||||
if (test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* SRR0 and SRR1 should be set correctly */
|
||||
if (mfspr(SRR0) != ptr ||
|
||||
mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE))
|
||||
mfspr(SRR1) != (MSR_SF | MSR_HV | 0x10000000 | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
@@ -556,16 +557,16 @@ int mmu_test_16(void)
|
||||
/* create a PTE for the second page without execute permission */
|
||||
map((void *)ptr2, (void *)mem2, PERM_RD | REF);
|
||||
/* this should fail due to second page being no-execute */
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* SRR0 and SRR1 should be set correctly */
|
||||
if (mfspr(SRR0) != ptr2 ||
|
||||
mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE))
|
||||
mfspr(SRR1) != (MSR_SF | MSR_HV | 0x10000000 | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
/* create a PTE for the second page with execute permission */
|
||||
map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF);
|
||||
/* this should succeed */
|
||||
if (!test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 3;
|
||||
return 0;
|
||||
}
|
||||
@@ -578,22 +579,22 @@ int mmu_test_17(void)
|
||||
/* create a PTE without the ref bit set */
|
||||
map((void *)ptr, (void *)mem, PERM_EX);
|
||||
/* this should fail */
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* SRR0 and SRR1 should be set correctly */
|
||||
if (mfspr(SRR0) != (long) ptr ||
|
||||
mfspr(SRR1) != (MSR_SF | 0x00040000 | MSR_IR | MSR_LE))
|
||||
mfspr(SRR1) != (MSR_SF | MSR_HV | 0x00040000 | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
/* create a PTE without ref or execute permission */
|
||||
unmap((void *)ptr);
|
||||
map((void *)ptr, (void *)mem, 0);
|
||||
/* this should fail */
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE))
|
||||
if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
|
||||
return 1;
|
||||
/* SRR0 and SRR1 should be set correctly */
|
||||
/* RC update fail bit should not be set */
|
||||
if (mfspr(SRR0) != (long) ptr ||
|
||||
mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE))
|
||||
mfspr(SRR1) != (MSR_SF | MSR_HV | 0x10000000 | MSR_IR | MSR_LE))
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -230,3 +230,63 @@ restore:
|
||||
ld %r0,16(%r1)
|
||||
mtlr %r0
|
||||
blr
|
||||
|
||||
.global do_lq
|
||||
do_lq:
|
||||
lq %r6,0(%r3)
|
||||
std %r6,0(%r4)
|
||||
std %r7,8(%r4)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
.global do_lq_np /* "non-preferred" form of lq */
|
||||
do_lq_np:
|
||||
mr %r7,%r3
|
||||
lq %r6,0(%r7)
|
||||
std %r6,0(%r4)
|
||||
std %r7,8(%r4)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
.global do_lq_bad /* illegal form of lq */
|
||||
do_lq_bad:
|
||||
mr %r6,%r3
|
||||
.long 0xe0c60000 /* lq %r6,0(%r6) */
|
||||
std %r6,0(%r4)
|
||||
std %r7,8(%r4)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
.global do_stq
|
||||
do_stq:
|
||||
ld %r8,0(%r4)
|
||||
ld %r9,8(%r4)
|
||||
stq %r8,0(%r3)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
/* big-endian versions of the above */
|
||||
.global do_lq_be
|
||||
do_lq_be:
|
||||
.long 0x0000c3e0
|
||||
.long 0x0000c4f8
|
||||
.long 0x0800e4f8
|
||||
.long 0x00006038
|
||||
.long 0x2000804e
|
||||
|
||||
.global do_lq_np_be /* "non-preferred" form of lq */
|
||||
do_lq_np_be:
|
||||
.long 0x781b677c
|
||||
.long 0x0000c7e0
|
||||
.long 0x0000c4f8
|
||||
.long 0x0800e4f8
|
||||
.long 0x00006038
|
||||
.long 0x2000804e
|
||||
|
||||
.global do_stq_be
|
||||
do_stq_be:
|
||||
.long 0x000004e9
|
||||
.long 0x080024e9
|
||||
.long 0x020003f9
|
||||
.long 0x00006038
|
||||
.long 0x2000804e
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
extern unsigned long callit(unsigned long arg1, unsigned long arg2,
|
||||
unsigned long fn, unsigned long msr);
|
||||
|
||||
extern void do_lq(void *src, unsigned long *regs);
|
||||
extern void do_lq_np(void *src, unsigned long *regs);
|
||||
extern void do_lq_bad(void *src, unsigned long *regs);
|
||||
extern void do_stq(void *dst, unsigned long *regs);
|
||||
extern void do_lq_be(void *src, unsigned long *regs);
|
||||
extern void do_lq_np_be(void *src, unsigned long *regs);
|
||||
extern void do_stq_be(void *dst, unsigned long *regs);
|
||||
|
||||
static inline void do_tlbie(unsigned long rb, unsigned long rs)
|
||||
{
|
||||
__asm__ volatile("tlbie %0,%1" : : "r" (rb), "r" (rs) : "memory");
|
||||
@@ -25,6 +33,8 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
|
||||
#define SPRG0 272
|
||||
#define SPRG1 273
|
||||
#define SPRG3 275
|
||||
#define HSRR0 314
|
||||
#define HSRR1 315
|
||||
#define PTCR 464
|
||||
|
||||
static inline unsigned long mfspr(int sprnum)
|
||||
@@ -294,6 +304,166 @@ int mode_test_6(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mode_test_7(void)
|
||||
{
|
||||
unsigned long quad[4] __attribute__((__aligned__(16)));
|
||||
unsigned long regs[2];
|
||||
unsigned long ret, msr;
|
||||
|
||||
/*
|
||||
* Test lq/stq in LE mode
|
||||
*/
|
||||
msr = MSR_SF | MSR_LE;
|
||||
quad[0] = 0x123456789abcdef0ul;
|
||||
quad[1] = 0xfafa5959bcbc3434ul;
|
||||
ret = callit((unsigned long)quad, (unsigned long)regs,
|
||||
(unsigned long)&do_lq, msr);
|
||||
if (ret)
|
||||
return ret | 1;
|
||||
if (regs[0] != quad[1] || regs[1] != quad[0])
|
||||
return 2;
|
||||
/* unaligned may give alignment interrupt */
|
||||
quad[2] = 0x0011223344556677ul;
|
||||
ret = callit((unsigned long)&quad[1], (unsigned long)regs,
|
||||
(unsigned long)&do_lq, msr);
|
||||
if (ret == 0) {
|
||||
if (regs[0] != quad[2] || regs[1] != quad[1])
|
||||
return 3;
|
||||
} else if (ret == 0x600) {
|
||||
if (mfspr(SPRG0) != (unsigned long) &do_lq ||
|
||||
mfspr(DAR) != (unsigned long) &quad[1])
|
||||
return ret | 4;
|
||||
} else
|
||||
return ret | 5;
|
||||
|
||||
/* try stq */
|
||||
regs[0] = 0x5238523852385238ul;
|
||||
regs[1] = 0x5239523952395239ul;
|
||||
ret = callit((unsigned long)quad, (unsigned long)regs,
|
||||
(unsigned long)&do_stq, msr);
|
||||
if (ret)
|
||||
return ret | 5;
|
||||
if (quad[0] != regs[1] || quad[1] != regs[0])
|
||||
return 6;
|
||||
regs[0] = 0x0172686966746564ul;
|
||||
regs[1] = 0xfe8d0badd00dabcdul;
|
||||
ret = callit((unsigned long)quad + 1, (unsigned long)regs,
|
||||
(unsigned long)&do_stq, msr);
|
||||
if (ret)
|
||||
return ret | 7;
|
||||
if (((quad[0] >> 8) | (quad[1] << 56)) != regs[1] ||
|
||||
((quad[1] >> 8) | (quad[2] << 56)) != regs[0])
|
||||
return 8;
|
||||
|
||||
/* try lq non-preferred form */
|
||||
quad[0] = 0x56789abcdef01234ul;
|
||||
quad[1] = 0x5959bcbc3434fafaul;
|
||||
ret = callit((unsigned long)quad, (unsigned long)regs,
|
||||
(unsigned long)&do_lq_np, msr);
|
||||
if (ret)
|
||||
return ret | 9;
|
||||
if (regs[0] != quad[1] || regs[1] != quad[0])
|
||||
return 10;
|
||||
/* unaligned should give alignment interrupt in uW implementation */
|
||||
quad[2] = 0x6677001122334455ul;
|
||||
ret = callit((unsigned long)&quad[1], (unsigned long)regs,
|
||||
(unsigned long)&do_lq_np, msr);
|
||||
if (ret == 0x600) {
|
||||
if (mfspr(SPRG0) != (unsigned long) &do_lq_np + 4 ||
|
||||
mfspr(DAR) != (unsigned long) &quad[1])
|
||||
return ret | 11;
|
||||
} else
|
||||
return 12;
|
||||
|
||||
/* make sure lq with rt = ra causes a HEAI interrupt */
|
||||
ret = callit((unsigned long)quad, (unsigned long)regs,
|
||||
(unsigned long)&do_lq_bad, msr);
|
||||
if (ret != 0xe40)
|
||||
return 13;
|
||||
if (mfspr(HSRR0) != (unsigned long)&do_lq_bad + 4)
|
||||
return 14;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mode_test_8(void)
|
||||
{
|
||||
unsigned long quad[4] __attribute__((__aligned__(16)));
|
||||
unsigned long regs[2];
|
||||
unsigned long ret, msr;
|
||||
|
||||
/*
|
||||
* Test lq/stq in BE mode
|
||||
*/
|
||||
msr = MSR_SF;
|
||||
quad[0] = 0x123456789abcdef0ul;
|
||||
quad[1] = 0xfafa5959bcbc3434ul;
|
||||
ret = callit((unsigned long)quad, (unsigned long)regs,
|
||||
(unsigned long)&do_lq_be, msr);
|
||||
if (ret)
|
||||
return ret | 1;
|
||||
if (regs[0] != quad[0] || regs[1] != quad[1]) {
|
||||
print_hex(regs[0], 16);
|
||||
print_string(" ");
|
||||
print_hex(regs[1], 16);
|
||||
print_string(" ");
|
||||
return 2;
|
||||
}
|
||||
/* don't expect alignment interrupt */
|
||||
quad[2] = 0x0011223344556677ul;
|
||||
ret = callit((unsigned long)&quad[1], (unsigned long)regs,
|
||||
(unsigned long)&do_lq_be, msr);
|
||||
if (ret == 0) {
|
||||
if (regs[0] != quad[1] || regs[1] != quad[2])
|
||||
return 3;
|
||||
} else
|
||||
return ret | 5;
|
||||
|
||||
/* try stq */
|
||||
regs[0] = 0x5238523852385238ul;
|
||||
regs[1] = 0x5239523952395239ul;
|
||||
ret = callit((unsigned long)quad, (unsigned long)regs,
|
||||
(unsigned long)&do_stq_be, msr);
|
||||
if (ret)
|
||||
return ret | 5;
|
||||
if (quad[0] != regs[0] || quad[1] != regs[1])
|
||||
return 6;
|
||||
regs[0] = 0x0172686966746564ul;
|
||||
regs[1] = 0xfe8d0badd00dabcdul;
|
||||
ret = callit((unsigned long)quad + 1, (unsigned long)regs,
|
||||
(unsigned long)&do_stq_be, msr);
|
||||
if (ret)
|
||||
return ret | 7;
|
||||
if (((quad[0] >> 8) | (quad[1] << 56)) != regs[0] ||
|
||||
((quad[1] >> 8) | (quad[2] << 56)) != regs[1]) {
|
||||
print_hex(quad[0], 16);
|
||||
print_string(" ");
|
||||
print_hex(quad[1], 16);
|
||||
print_string(" ");
|
||||
print_hex(quad[2], 16);
|
||||
print_string(" ");
|
||||
return 8;
|
||||
}
|
||||
|
||||
/* try lq non-preferred form */
|
||||
quad[0] = 0x56789abcdef01234ul;
|
||||
quad[1] = 0x5959bcbc3434fafaul;
|
||||
ret = callit((unsigned long)quad, (unsigned long)regs,
|
||||
(unsigned long)&do_lq_np_be, msr);
|
||||
if (ret)
|
||||
return ret | 9;
|
||||
if (regs[0] != quad[0] || regs[1] != quad[1])
|
||||
return 10;
|
||||
/* unaligned should not give alignment interrupt in uW implementation */
|
||||
quad[2] = 0x6677001122334455ul;
|
||||
ret = callit((unsigned long)&quad[1], (unsigned long)regs,
|
||||
(unsigned long)&do_lq_np_be, msr);
|
||||
if (ret)
|
||||
return ret | 11;
|
||||
if (regs[0] != quad[1] || regs[1] != quad[2])
|
||||
return 12;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fail = 0;
|
||||
|
||||
void do_test(int num, int (*test)(void))
|
||||
@@ -338,6 +508,8 @@ int main(void)
|
||||
do_test(4, mode_test_4);
|
||||
do_test(5, mode_test_5);
|
||||
do_test(6, mode_test_6);
|
||||
do_test(7, mode_test_7);
|
||||
do_test(8, mode_test_8);
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
@@ -245,3 +245,23 @@ test_pstw:
|
||||
pstw %r3,wvar(0)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
.globl test_plq
|
||||
test_plq:
|
||||
nop
|
||||
nop
|
||||
plq %r4,qvar(0)
|
||||
std %r4,0(%r3)
|
||||
std %r5,8(%r3)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
.globl test_pstq
|
||||
test_pstq:
|
||||
nop
|
||||
nop
|
||||
ld %r4,0(%r3)
|
||||
ld %r5,8(%r3)
|
||||
pstq %r4,qvar(0)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define MSR_LE 0x1
|
||||
#define MSR_DR 0x10
|
||||
#define MSR_IR 0x20
|
||||
#define MSR_HV 0x1000000000000000ul
|
||||
#define MSR_SF 0x8000000000000000ul
|
||||
|
||||
#define DSISR 18
|
||||
@@ -32,6 +33,8 @@ extern long test_pstd(long arg);
|
||||
extern long test_psth(long arg);
|
||||
extern long test_pstw(long arg);
|
||||
extern long test_plfd(long arg);
|
||||
extern long test_plq(long arg);
|
||||
extern long test_pstq(long arg);
|
||||
|
||||
static inline unsigned long mfspr(int sprnum)
|
||||
{
|
||||
@@ -103,7 +106,7 @@ long int prefix_test_2(void)
|
||||
return 1;
|
||||
if (mfspr(SRR0) != (unsigned long)&test_paddi_mis + 8)
|
||||
return 2;
|
||||
if (mfspr(SRR1) != (MSR_SF | MSR_LE | (1ul << (63 - 35)) | (1ul << (63 - 34))))
|
||||
if (mfspr(SRR1) != (MSR_SF | MSR_HV | MSR_LE | (1ul << (63 - 35)) | (1ul << (63 - 34))))
|
||||
return 3;
|
||||
|
||||
ret = trapit((long)&x, test_plfd);
|
||||
@@ -111,7 +114,7 @@ long int prefix_test_2(void)
|
||||
return ret;
|
||||
if (mfspr(SRR0) != (unsigned long)&test_plfd + 8)
|
||||
return 6;
|
||||
if (mfspr(SRR1) != (MSR_SF | MSR_LE | (1ul << (63 - 34))))
|
||||
if (mfspr(SRR1) != (MSR_SF | MSR_HV | MSR_LE | (1ul << (63 - 34))))
|
||||
return 7;
|
||||
return 0;
|
||||
}
|
||||
@@ -182,6 +185,39 @@ long int prefix_test_3(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long qvar[2] __attribute__((__aligned__(16)));
|
||||
#define V1 0x678912345a5a2b2bull
|
||||
#define V2 0xa0549922bbccddeeull
|
||||
|
||||
/* test plq and pstq */
|
||||
long int prefix_test_4(void)
|
||||
{
|
||||
long int ret;
|
||||
unsigned long x[2];
|
||||
|
||||
qvar[0] = V1;
|
||||
qvar[1] = V2;
|
||||
ret = trapit((long)&x, test_plq);
|
||||
if (ret)
|
||||
return ret | 1;
|
||||
if (x[0] != V1 || x[1] != V2) {
|
||||
print_hex(x[0], 16, " ");
|
||||
print_hex(x[1], 16, " ");
|
||||
return 2;
|
||||
}
|
||||
x[0] = ~V2;
|
||||
x[1] = ~V1;
|
||||
ret = trapit((long)&x, test_pstq);
|
||||
if (ret)
|
||||
return ret | 3;
|
||||
if (qvar[0] != ~V2 || qvar[1] != ~V1) {
|
||||
print_hex(qvar[0], 16, " ");
|
||||
print_hex(qvar[1], 16, " ");
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fail = 0;
|
||||
|
||||
void do_test(int num, long int (*test)(void))
|
||||
@@ -209,6 +245,7 @@ int main(void)
|
||||
do_test(1, prefix_test_1);
|
||||
do_test(2, prefix_test_2);
|
||||
do_test(3, prefix_test_3);
|
||||
do_test(4, prefix_test_4);
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
@@ -155,3 +155,31 @@ call_ret:
|
||||
ld %r31,248(%r1)
|
||||
addi %r1,%r1,256
|
||||
blr
|
||||
|
||||
.global do_lqarx
|
||||
do_lqarx:
|
||||
/* r3 = src, r4 = regs */
|
||||
lqarx %r10,0,%r3
|
||||
std %r10,0(%r4)
|
||||
std %r11,8(%r4)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
.global do_lqarx_bad
|
||||
do_lqarx_bad:
|
||||
/* r3 = src, r4 = regs */
|
||||
.long 0x7d405228 /* lqarx %r10,0,%r10 */
|
||||
std %r10,0(%r4)
|
||||
std %r11,8(%r4)
|
||||
li %r3,0
|
||||
blr
|
||||
|
||||
.global do_stqcx
|
||||
do_stqcx:
|
||||
/* r3 = dest, r4 = regs, return CR */
|
||||
ld %r10,0(%r4)
|
||||
ld %r11,8(%r4)
|
||||
stqcx. %r10,0,%r3
|
||||
mfcr %r3
|
||||
oris %r3,%r3,1 /* to distinguish from trap number */
|
||||
blr
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
extern unsigned long callit(unsigned long arg1, unsigned long arg2,
|
||||
unsigned long (*fn)(unsigned long, unsigned long));
|
||||
|
||||
extern unsigned long do_lqarx(unsigned long src, unsigned long regs);
|
||||
extern unsigned long do_lqarx_bad(unsigned long src, unsigned long regs);
|
||||
extern unsigned long do_stqcx(unsigned long dst, unsigned long regs);
|
||||
|
||||
#define DSISR 18
|
||||
#define DAR 19
|
||||
#define SRR0 26
|
||||
@@ -180,6 +184,63 @@ int resv_test_2(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* test lqarx/stqcx */
|
||||
int resv_test_3(void)
|
||||
{
|
||||
unsigned long x[4] __attribute__((__aligned__(16)));
|
||||
unsigned long y[2], regs[2];
|
||||
unsigned long ret, offset;
|
||||
int count;
|
||||
|
||||
x[0] = 0x7766554433221100ul;
|
||||
x[1] = 0xffeeddccbbaa9988ul;
|
||||
y[0] = 0x0badcafef00dd00dul;
|
||||
y[1] = 0xdeadbeef07070707ul;
|
||||
for (count = 0; count < 1000; ++count) {
|
||||
ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx);
|
||||
if (ret)
|
||||
return ret | 1;
|
||||
ret = callit((unsigned long)x, (unsigned long)y, do_stqcx);
|
||||
if (ret < 0x10000)
|
||||
return ret | 2;
|
||||
if (ret & 0x20000000)
|
||||
break;
|
||||
}
|
||||
if (count == 1000)
|
||||
return 3;
|
||||
if (x[0] != y[1] || x[1] != y[0])
|
||||
return 4;
|
||||
if (regs[1] != 0x7766554433221100ul || regs[0] != 0xffeeddccbbaa9988ul)
|
||||
return 5;
|
||||
ret = callit((unsigned long)x, (unsigned long)regs, do_stqcx);
|
||||
if (ret < 0x10000 || (ret & 0x20000000))
|
||||
return ret | 12;
|
||||
/* test alignment interrupts */
|
||||
for (offset = 0; offset < 16; ++offset) {
|
||||
ret = callit((unsigned long)x + offset, (unsigned long)regs, do_lqarx);
|
||||
if (ret == 0 && (offset & 15) != 0)
|
||||
return 6;
|
||||
if (ret == 0x600) {
|
||||
if ((offset & 15) == 0)
|
||||
return ret + 7;
|
||||
} else if (ret)
|
||||
return ret;
|
||||
ret = callit((unsigned long)x + offset, (unsigned long)y, do_stqcx);
|
||||
if (ret >= 0x10000 && (offset & 15) != 0)
|
||||
return 8;
|
||||
if (ret == 0x600) {
|
||||
if ((offset & 15) == 0)
|
||||
return ret + 9;
|
||||
} else if (ret < 0x10000)
|
||||
return ret;
|
||||
}
|
||||
/* test illegal interrupt for bad lqarx case */
|
||||
ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx_bad);
|
||||
if (ret != 0xe40)
|
||||
return ret + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fail = 0;
|
||||
|
||||
void do_test(int num, int (*test)(void))
|
||||
@@ -204,6 +265,7 @@ int main(void)
|
||||
|
||||
do_test(1, resv_test_1);
|
||||
do_test(2, resv_test_2);
|
||||
do_test(3, resv_test_3);
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,3 +4,5 @@ test 03:PASS
|
||||
test 04:PASS
|
||||
test 05:PASS
|
||||
test 06:PASS
|
||||
test 07:PASS
|
||||
test 08:PASS
|
||||
|
||||
Binary file not shown.
@@ -1,3 +1,4 @@
|
||||
test 01:PASS
|
||||
test 02:PASS
|
||||
test 03:PASS
|
||||
test 04:PASS
|
||||
|
||||
Binary file not shown.
@@ -1,2 +1,3 @@
|
||||
test 01:PASS
|
||||
test 02:PASS
|
||||
test 03:PASS
|
||||
|
||||
Binary file not shown.
@@ -115,7 +115,7 @@ __isr:
|
||||
std %r29, 29*8(%r1)
|
||||
std %r30, 30*8(%r1)
|
||||
std %r31, 31*8(%r1)
|
||||
mfsrr0 %r0
|
||||
mfhsrr0 %r0
|
||||
std %r0, SAVE_NIA*8(%r1)
|
||||
mflr %r0
|
||||
std %r0, SAVE_LR*8(%r1)
|
||||
@@ -123,7 +123,7 @@ __isr:
|
||||
std %r0, SAVE_CTR*8(%r1)
|
||||
mfcr %r0
|
||||
std %r0, SAVE_CR*8(%r1)
|
||||
mfsrr1 %r0
|
||||
mfhsrr1 %r0
|
||||
std %r0, SAVE_SRR1*8(%r1)
|
||||
|
||||
stdu %r1,-STACK_FRAME_C_MINIMAL(%r1)
|
||||
|
||||
@@ -72,11 +72,15 @@ begin
|
||||
variable vec : integer range 0 to 16#fff#;
|
||||
variable srr1 : std_ulogic_vector(15 downto 0);
|
||||
variable intr : std_ulogic;
|
||||
variable hvi : std_ulogic;
|
||||
variable scv : std_ulogic;
|
||||
variable intr_page : std_ulogic_vector(4 downto 0);
|
||||
begin
|
||||
w_out <= WritebackToRegisterFileInit;
|
||||
c_out <= WritebackToCrFileInit;
|
||||
f := WritebackToFetch1Init;
|
||||
vec := 0;
|
||||
hvi := '0';
|
||||
|
||||
complete_out <= instr_tag_init;
|
||||
if e_in.valid = '1' then
|
||||
@@ -93,9 +97,16 @@ begin
|
||||
interrupt_out.intr <= intr;
|
||||
|
||||
srr1 := (others => '0');
|
||||
intr_page := 5x"0";
|
||||
scv := '0';
|
||||
if e_in.interrupt = '1' then
|
||||
vec := e_in.intr_vec;
|
||||
srr1 := e_in.srr1;
|
||||
hvi := e_in.hv_intr;
|
||||
scv := e_in.is_scv;
|
||||
if e_in.is_scv = '1' then
|
||||
intr_page := 5x"17";
|
||||
end if;
|
||||
elsif l_in.interrupt = '1' then
|
||||
vec := l_in.intr_vec;
|
||||
srr1 := l_in.srr1;
|
||||
@@ -103,7 +114,9 @@ begin
|
||||
vec := fp_in.intr_vec;
|
||||
srr1 := fp_in.srr1;
|
||||
end if;
|
||||
interrupt_out.hv_intr <= hvi;
|
||||
interrupt_out.srr1 <= srr1;
|
||||
interrupt_out.scv_int <= scv;
|
||||
|
||||
if intr = '0' then
|
||||
if e_in.write_enable = '1' then
|
||||
@@ -161,7 +174,7 @@ begin
|
||||
|
||||
-- Outputs to fetch1
|
||||
f.interrupt := intr;
|
||||
f.intr_vec := std_ulogic_vector(to_unsigned(vec, 12));
|
||||
f.intr_vec := intr_page & std_ulogic_vector(to_unsigned(vec, 12));
|
||||
f.redirect := e_in.redirect;
|
||||
f.redirect_nia := e_in.write_data;
|
||||
f.br_nia := e_in.last_nia;
|
||||
|
||||
Reference in New Issue
Block a user