Merge pull request #440 from paulusmack/compliance

More compliance improvements - [H]DEXCR, no-op SPRs, writable TB
master
Paul Mackerras 10 hours ago committed by GitHub
commit c5abe3c0a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -39,6 +39,8 @@ package common is
constant SPR_DAR : spr_num_t := 19; constant SPR_DAR : spr_num_t := 19;
constant SPR_TB : spr_num_t := 268; constant SPR_TB : spr_num_t := 268;
constant SPR_TBU : spr_num_t := 269; constant SPR_TBU : spr_num_t := 269;
constant SPR_TBLW : spr_num_t := 284;
constant SPR_TBUW : spr_num_t := 285;
constant SPR_DEC : spr_num_t := 22; constant SPR_DEC : spr_num_t := 22;
constant SPR_SRR0 : spr_num_t := 26; constant SPR_SRR0 : spr_num_t := 26;
constant SPR_SRR1 : spr_num_t := 27; constant SPR_SRR1 : spr_num_t := 27;
@ -71,6 +73,14 @@ package common is
constant SPR_DAWRX1 : spr_num_t := 189; constant SPR_DAWRX1 : spr_num_t := 189;
constant SPR_HASHKEYR : spr_num_t := 468; constant SPR_HASHKEYR : spr_num_t := 468;
constant SPR_HASHPKEYR : spr_num_t := 469; constant SPR_HASHPKEYR : spr_num_t := 469;
constant SPR_DEXCR : spr_num_t := 828;
constant SPR_DEXCRU : spr_num_t := 812;
constant SPR_HDEXCR : spr_num_t := 471;
constant SPR_HDEXCU : spr_num_t := 455;
constant SPR_NOOP0 : spr_num_t := 808;
constant SPR_NOOP1 : spr_num_t := 809;
constant SPR_NOOP2 : spr_num_t := 810;
constant SPR_NOOP3 : spr_num_t := 811;


-- PMU registers -- PMU registers
constant SPR_UPMC1 : spr_num_t := 771; constant SPR_UPMC1 : spr_num_t := 771;
@ -167,6 +177,7 @@ package common is
ispmu : std_ulogic; ispmu : std_ulogic;
ronly : std_ulogic; ronly : std_ulogic;
wonly : std_ulogic; wonly : std_ulogic;
noop : std_ulogic;
end record; end record;
constant spr_id_init : spr_id := (sel => "0000", others => '0'); constant spr_id_init : spr_id := (sel => "0000", others => '0');


@ -184,6 +195,7 @@ package common is
constant SPRSEL_DSCR : spr_selector := 4x"b"; constant SPRSEL_DSCR : spr_selector := 4x"b";
constant SPRSEL_PIR : spr_selector := 4x"c"; constant SPRSEL_PIR : spr_selector := 4x"c";
constant SPRSEL_CIABR : spr_selector := 4x"d"; constant SPRSEL_CIABR : spr_selector := 4x"d";
constant SPRSEL_DEXCR : spr_selector := 4x"e";
constant SPRSEL_XER : spr_selector := 4x"f"; constant SPRSEL_XER : spr_selector := 4x"f";


-- FSCR and HFSCR bit numbers -- FSCR and HFSCR bit numbers
@ -266,6 +278,16 @@ package common is
pri : std_ulogic_vector(31 downto 0); -- 8 bits each for 4 cpus pri : std_ulogic_vector(31 downto 0); -- 8 bits each for 4 cpus
end record; end record;


-- Bits in each half of DEXCR and HDEXCR
subtype aspect_bits_t is std_ulogic_vector(4 downto 0);
constant aspect_bits_init : aspect_bits_t := (others => '1');
-- Bit numbers in aspect_bits_t
constant DEXCR_SBHE : integer := 4; -- speculative branch hint enable
constant DEXCR_IBRTPD : integer := 3; -- indirect branch recurrent target prediction disable
constant DEXCR_SRAPD : integer := 2; -- subroutine return address prediction disable
constant DEXCR_NPHIE : integer := 1; -- non-privileged hash instruction enable
constant DEXCR_PHIE : integer := 0; -- privileged hash instruction enable

-- This needs to die... -- This needs to die...
type ctrl_t is record type ctrl_t is record
wait_state: std_ulogic; wait_state: std_ulogic;
@ -287,14 +309,26 @@ package common is
heir: std_ulogic_vector(63 downto 0); heir: std_ulogic_vector(63 downto 0);
dscr: std_ulogic_vector(24 downto 0); dscr: std_ulogic_vector(24 downto 0);
ciabr: std_ulogic_vector(63 downto 0); ciabr: std_ulogic_vector(63 downto 0);
dexcr_pnh: aspect_bits_t;
dexcr_pro: aspect_bits_t;
hdexcr_hyp: aspect_bits_t;
hdexcr_enf: aspect_bits_t;
end record; end record;
constant ctrl_t_init : ctrl_t := constant ctrl_t_init : ctrl_t :=
(wait_state => '0', run => '1', xer_low => 18x"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', 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', hfscr_ic => x"0", hfscr_pref => '1', hfscr_tar => '1', hfscr_dscr => '1', hfscr_fp => '1',
dscr => (others => '0'), dscr => (others => '0'),
dexcr_pnh => aspect_bits_init, dexcr_pro => aspect_bits_init,
hdexcr_hyp => aspect_bits_init, hdexcr_enf => aspect_bits_init,
others => (others => '0')); others => (others => '0'));


type timebase_ctrl is record
reset : std_ulogic;
rd_prot : std_ulogic; -- read-protect => userspace can't read TB
freeze : std_ulogic;
end record;

type Fetch1ToIcacheType is record type Fetch1ToIcacheType is record
req: std_ulogic; req: std_ulogic;
fetch_fail : std_ulogic; fetch_fail : std_ulogic;
@ -604,6 +638,7 @@ package common is
e2stall : std_ulogic; e2stall : std_ulogic;
msr : std_ulogic_vector(63 downto 0); msr : std_ulogic_vector(63 downto 0);
hashkey : std_ulogic_vector(63 downto 0); hashkey : std_ulogic_vector(63 downto 0);
hash_enable : std_ulogic;
end record; end record;
constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type :=
(valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0', (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0',
@ -616,7 +651,7 @@ package common is
length => (others => '0'), length => (others => '0'),
mode_32bit => '0', is_32bit => '0', prefixed => '0', mode_32bit => '0', is_32bit => '0', prefixed => '0',
repeat => '0', second => '0', e2stall => '0', repeat => '0', second => '0', e2stall => '0',
msr => (others => '0'), hashkey => (others => '0')); msr => (others => '0'), hashkey => (others => '0'), hash_enable => '0');


type Loadstore1ToExecute1Type is record type Loadstore1ToExecute1Type is record
busy : std_ulogic; busy : std_ulogic;

@ -31,8 +31,8 @@ entity core is
-- Alternate reset (0xffff0000) for use by DRAM init fw -- Alternate reset (0xffff0000) for use by DRAM init fw
alt_reset : in std_ulogic; alt_reset : in std_ulogic;


-- Global timebase -- Global timebase control
timebase : in std_ulogic_vector(63 downto 0); tb_ctrl : in timebase_ctrl;


-- Wishbone interface -- Wishbone interface
wishbone_insn_in : in wishbone_slave_out; wishbone_insn_in : in wishbone_slave_out;
@ -309,6 +309,7 @@ begin
busy_in => decode2_busy_in, busy_in => decode2_busy_in,
stall_out => decode2_stall_out, stall_out => decode2_stall_out,
flush_in => flush, flush_in => flush,
tb_ctrl => tb_ctrl,
complete_in => complete, complete_in => complete,
stopped_out => dbg_core_is_stopped, stopped_out => dbg_core_is_stopped,
d_in => decode1_to_decode2, d_in => decode1_to_decode2,
@ -376,7 +377,7 @@ begin
port map ( port map (
clk => clk, clk => clk,
rst => rst_ex1, rst => rst_ex1,
timebase => timebase, tb_ctrl => tb_ctrl,
flush_in => flush, flush_in => flush,
busy_out => ex1_busy_out, busy_out => ex1_busy_out,
e_in => decode2_to_execute1, e_in => decode2_to_execute1,

@ -457,11 +457,20 @@ architecture behaviour of decode1 is
i.ispmu := '0'; i.ispmu := '0';
i.ronly := '0'; i.ronly := '0';
i.wonly := '0'; i.wonly := '0';
i.noop := '0';
case sprn is case sprn is
when SPR_TB => when SPR_TB =>
i.sel := SPRSEL_TB; i.sel := SPRSEL_TB;
i.ronly := '1';
when SPR_TBU => when SPR_TBU =>
i.sel := SPRSEL_TBU; i.sel := SPRSEL_TBU;
i.ronly := '1';
when SPR_TBLW =>
i.sel := SPRSEL_TB;
i.wonly := '1';
when SPR_TBUW =>
i.sel := SPRSEL_TB;
i.wonly := '1';
when SPR_DEC => when SPR_DEC =>
i.sel := SPRSEL_DEC; i.sel := SPRSEL_DEC;
when SPR_PVR => when SPR_PVR =>
@ -499,6 +508,13 @@ architecture behaviour of decode1 is
i.sel := SPRSEL_PIR; i.sel := SPRSEL_PIR;
when SPR_CIABR => when SPR_CIABR =>
i.sel := SPRSEL_CIABR; i.sel := SPRSEL_CIABR;
when SPR_DEXCR | SPR_HDEXCR =>
i.sel := SPRSEL_DEXCR;
when SPR_DEXCRU | SPR_HDEXCU =>
i.sel := SPRSEL_DEXCR;
i.ronly := '1';
when SPR_NOOP0 | SPR_NOOP1 | SPR_NOOP2 | SPR_NOOP3 =>
i.noop := '1';
when others => when others =>
i.valid := '0'; i.valid := '0';
end case; end case;

@ -27,6 +27,8 @@ entity decode2 is


flush_in: in std_ulogic; flush_in: in std_ulogic;


tb_ctrl : timebase_ctrl;

d_in : in Decode1ToDecode2Type; d_in : in Decode1ToDecode2Type;


e_out : out Decode2ToExecute1Type; e_out : out Decode2ToExecute1Type;
@ -696,9 +698,11 @@ begin
if op = OP_MFSPR then if op = OP_MFSPR then
if d_in.ram_spr.valid = '1' then if d_in.ram_spr.valid = '1' then
v.e.result_sel := "101"; -- ramspr_result v.e.result_sel := "101"; -- ramspr_result
elsif d_in.spr_info.valid = '0' or d_in.spr_info.wonly = '1' then elsif d_in.spr_info.valid = '0' or d_in.spr_info.wonly = '1' or
d_in.spr_info.noop = '1' then
-- Privileged mfspr to invalid/unimplemented SPR numbers -- Privileged mfspr to invalid/unimplemented SPR numbers
-- writes the contents of RT back to RT (i.e. it's a no-op) -- writes the contents of RT back to RT (i.e. it's a no-op)
-- as does any mfspr from the reserved/noop SPR numbers
v.e.result_sel := "001"; -- logical_result v.e.result_sel := "001"; -- logical_result
end if; end if;
end if; end if;
@ -706,6 +710,11 @@ begin
if (op = OP_MFSPR or op = OP_MTSPR) and d_in.insn(20) = '1' then if (op = OP_MFSPR or op = OP_MTSPR) and d_in.insn(20) = '1' then
v.e.privileged := '1'; v.e.privileged := '1';
end if; end if;
-- Reading TB is privileged if syscon_tb_ctrl.rd_protect is 1
if tb_ctrl.rd_prot = '1' and op = OP_MFSPR and d_in.spr_info.valid = '1' and
(d_in.spr_info.sel = SPRSEL_TB or d_in.spr_info.sel = SPRSEL_TBU) then
v.e.privileged := '1';
end if;
v.e.prefixed := d_in.prefixed; v.e.prefixed := d_in.prefixed;
v.e.prefix := d_in.prefix; v.e.prefix := d_in.prefix;
v.e.illegal_suffix := d_in.illegal_suffix; v.e.illegal_suffix := d_in.illegal_suffix;

@ -34,7 +34,7 @@ entity execute1 is
ext_irq_in : std_ulogic; ext_irq_in : std_ulogic;
interrupt_in : WritebackToExecute1Type; interrupt_in : WritebackToExecute1Type;


timebase : std_ulogic_vector(63 downto 0); tb_ctrl : timebase_ctrl;


-- asynchronous -- asynchronous
l_out : out Execute1ToLoadstore1Type; l_out : out Execute1ToLoadstore1Type;
@ -101,6 +101,8 @@ architecture behaviour of execute1 is
write_ciabr : std_ulogic; write_ciabr : std_ulogic;
enter_wait : std_ulogic; enter_wait : std_ulogic;
scv_trap : std_ulogic; scv_trap : std_ulogic;
write_tbl : std_ulogic;
write_tbu : std_ulogic;
end record; end record;
constant side_effect_init : side_effect_type := (others => '0'); constant side_effect_init : side_effect_type := (others => '0');


@ -279,6 +281,10 @@ architecture behaviour of execute1 is


signal stage2_stall : std_ulogic; signal stage2_stall : std_ulogic;


signal timebase : std_ulogic_vector(63 downto 0);
signal tb_next : std_ulogic_vector(63 downto 0);
signal tb_carry : std_ulogic;

type privilege_level is (USER, SUPER); type privilege_level is (USER, SUPER);
type op_privilege_array is array(insn_type_t) of privilege_level; type op_privilege_array is array(insn_type_t) of privilege_level;
constant op_privilege: op_privilege_array := ( constant op_privilege: op_privilege_array := (
@ -425,6 +431,32 @@ architecture behaviour of execute1 is
return ret; return ret;
end; end;


-- return contents of DEXCR or HDEXCR
-- top 32 bits are zeroed for access via non-privileged number
function assemble_dexcr(c: ctrl_t; insn: std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
variable ret : std_ulogic_vector(63 downto 0);
variable spr : std_ulogic_vector(9 downto 0);
variable dexh, dexl : aspect_bits_t;
begin
ret := (others => '0');
spr := insn(15 downto 11) & insn(20 downto 16);
if spr(9) = '1' then
dexh := c.dexcr_pnh;
dexl := c.dexcr_pro;
else
dexh := c.hdexcr_hyp;
dexl := c.hdexcr_enf;
end if;
if spr(4) = '0' then
dexl := (others => '0');
end if;
ret := dexh(DEXCR_SBHE) & "00" & dexh(DEXCR_IBRTPD) & dexh(DEXCR_SRAPD) &
dexh(DEXCR_NPHIE) & dexh(DEXCR_PHIE) & 25x"0" &
dexl(DEXCR_SBHE) & "00" & dexl(DEXCR_IBRTPD) & dexl(DEXCR_SRAPD) &
dexl(DEXCR_NPHIE) & dexl(DEXCR_PHIE) & 25x"0";
return ret;
end;

-- Tell vivado to keep the hierarchy for the random module so that the -- Tell vivado to keep the hierarchy for the random module so that the
-- net names in the xdc file match. -- net names in the xdc file match.
attribute keep_hierarchy : string; attribute keep_hierarchy : string;
@ -527,6 +559,43 @@ begin
p_out => pmu_to_x p_out => pmu_to_x
); );


-- Timebase just increments at the system clock frequency.
-- Ideally it would (appear to) run at 512MHz like IBM POWER systems,
-- but Linux seems to cope OK with it being 100MHz or whatever.
tbase: process(clk)
begin
if rising_edge(clk) then
if tb_ctrl.reset = '1' then
timebase <= (others => '0');
tb_carry <= '0';
else
timebase <= tb_next;
tb_carry <= and(tb_next(31 downto 0));
end if;
end if;
end process;

tbase_comb: process(all)
variable thi, tlo : std_ulogic_vector(31 downto 0);
variable carry : std_ulogic;
begin
tlo := timebase(31 downto 0);
thi := timebase(63 downto 32);
carry := '0';
if stage2_stall = '0' and ex1.se.write_tbl = '1' then
tlo := ex1.e.write_data(31 downto 0);
elsif tb_ctrl.freeze = '0' then
tlo := std_ulogic_vector(unsigned(tlo) + 1);
carry := tb_carry;
end if;
if stage2_stall = '0' and ex1.se.write_tbu = '1' then
thi := ex1.e.write_data(31 downto 0);
else
thi := std_ulogic_vector(unsigned(thi) + carry);
end if;
tb_next <= thi & tlo;
end process;

dbg_ctrl_out <= ctrl; dbg_ctrl_out <= ctrl;
log_rd_addr <= ex2.log_addr_spr; log_rd_addr <= ex2.log_addr_spr;


@ -1306,7 +1375,7 @@ begin
when OP_DARN => when OP_DARN =>
when OP_MFMSR => when OP_MFMSR =>
when OP_MFSPR => when OP_MFSPR =>
if e_in.spr_is_ram = '1' then if e_in.spr_is_ram = '1' or e_in.spr_select.noop = '1' then
if e_in.valid = '1' and not is_X(e_in.insn) then if e_in.valid = '1' and not is_X(e_in.insn) then
report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
"=" & to_hstring(alu_result); "=" & to_hstring(alu_result);
@ -1398,6 +1467,10 @@ begin
v.se.write_dscr := '1'; v.se.write_dscr := '1';
when SPRSEL_CIABR => when SPRSEL_CIABR =>
v.se.write_ciabr := '1'; v.se.write_ciabr := '1';
when SPRSEL_TB =>
v.se.write_tbl := '1';
when SPRSEL_TBU =>
v.se.write_tbu := '1';
when others => when others =>
end case; end case;
end if; end if;
@ -1600,6 +1673,7 @@ begin
variable go : std_ulogic; variable go : std_ulogic;
variable bypass_valid : std_ulogic; variable bypass_valid : std_ulogic;
variable is_scv : std_ulogic; variable is_scv : std_ulogic;
variable dex : aspect_bits_t;
begin begin
v := ex1; v := ex1;
if busy_out = '0' then if busy_out = '0' then
@ -1735,6 +1809,13 @@ begin
bperm_start <= go and actions.start_bperm; bperm_start <= go and actions.start_bperm;
pmu_trace <= go and actions.do_trace; pmu_trace <= go and actions.do_trace;


-- evaluate DEXCR/HDEXCR bits that apply at present
if ex1.msr(MSR_PR) = '0' then
dex := ctrl.hdexcr_hyp;
else
dex := ctrl.dexcr_pro or ctrl.hdexcr_enf;
end if;

if not HAS_FPU and ex1.div_in_progress = '1' then if not HAS_FPU and ex1.div_in_progress = '1' then
v.div_in_progress := not divider_to_x.valid; v.div_in_progress := not divider_to_x.valid;
v.busy := not divider_to_x.valid; v.busy := not divider_to_x.valid;
@ -1850,6 +1931,11 @@ begin
lv.second := e_in.second; lv.second := e_in.second;
lv.e2stall := fp_in.f2stall; lv.e2stall := fp_in.f2stall;
lv.hashkey := ramspr_odd; lv.hashkey := ramspr_odd;
if e_in.insn(7) = '0' then
lv.hash_enable := dex(DEXCR_PHIE);
else
lv.hash_enable := dex(DEXCR_NPHIE);
end if;


-- Outputs to FPU -- Outputs to FPU
fv.op := e_in.insn_type; fv.op := e_in.insn_type;
@ -1897,6 +1983,7 @@ begin
39x"0" & ctrl.dscr when SPRSEL_DSCR, 39x"0" & ctrl.dscr when SPRSEL_DSCR,
56x"0" & std_ulogic_vector(to_unsigned(CPU_INDEX, 8)) when SPRSEL_PIR, 56x"0" & std_ulogic_vector(to_unsigned(CPU_INDEX, 8)) when SPRSEL_PIR,
ctrl.ciabr when SPRSEL_CIABR, ctrl.ciabr when SPRSEL_CIABR,
assemble_dexcr(ctrl, ex1.insn) when SPRSEL_DEXCR,
assemble_xer(ex1.e.xerc, ctrl.xer_low) when others; assemble_xer(ex1.e.xerc, ctrl.xer_low) when others;


stage2_stall <= l_in.l2stall or fp_in.f2stall; stage2_stall <= l_in.l2stall or fp_in.f2stall;

@ -67,6 +67,9 @@
#define SYS_REG_GIT_IS_DIRTY (1ull << 63) #define SYS_REG_GIT_IS_DIRTY (1ull << 63)
#define SYS_REG_CPU_CTRL 0x58 #define SYS_REG_CPU_CTRL 0x58
#define SYS_REG_CPU_CTRL_ENABLE 0xff #define SYS_REG_CPU_CTRL_ENABLE 0xff
#define SYS_REG_TB_CTRL 0x60
#define SYS_REG_TB_CTRL_FREEZE 0x01
#define SYS_REG_TB_CTRL_RD_PROTECT 0x02


/* /*
* Register definitions for the potato UART * Register definitions for the potato UART

@ -565,6 +565,7 @@ begin
variable sprn : std_ulogic_vector(9 downto 0); variable sprn : std_ulogic_vector(9 downto 0);
variable misaligned : std_ulogic; variable misaligned : std_ulogic;
variable addr_mask : std_ulogic_vector(2 downto 0); variable addr_mask : std_ulogic_vector(2 downto 0);
variable hash_nop : std_ulogic;
begin begin
v := request_init; v := request_init;
sprn := l_in.insn(15 downto 11) & l_in.insn(20 downto 16); sprn := l_in.insn(15 downto 11) & l_in.insn(20 downto 16);
@ -641,7 +642,7 @@ begin
if l_in.repeat = '1' and l_in.update = '0' and addr(3) /= l_in.second then if l_in.repeat = '1' and l_in.update = '0' and addr(3) /= l_in.second then
misaligned := '1'; misaligned := '1';
end if; end if;
v.align_intr := (l_in.reserve or l_in.hash) and misaligned; v.align_intr := (l_in.reserve or (l_in.hash and l_in.hash_enable)) and misaligned;


v.atomic_first := not misaligned and not l_in.second; v.atomic_first := not misaligned and not l_in.second;
v.atomic_last := not misaligned and (l_in.second or not l_in.repeat); v.atomic_last := not misaligned and (l_in.second or not l_in.repeat);
@ -661,6 +662,7 @@ begin
end if; end if;
end if; end if;


hash_nop := '0';
case l_in.op is case l_in.op is
when OP_SYNC => when OP_SYNC =>
v.sync := '1'; v.sync := '1';
@ -671,6 +673,7 @@ begin
v.touch := '1'; v.touch := '1';
end if; end if;
v.hashst := l_in.hash; v.hashst := l_in.hash;
hash_nop := not l_in.hash_enable;
when OP_LOAD => when OP_LOAD =>
if l_in.update = '0' or l_in.second = '0' then if l_in.update = '0' or l_in.second = '0' then
v.load := '1'; v.load := '1';
@ -686,6 +689,7 @@ begin
v.do_update := '1'; v.do_update := '1';
end if; end if;
v.hashcmp := l_in.hash; v.hashcmp := l_in.hash;
hash_nop := not l_in.hash_enable;
when OP_DCBF => when OP_DCBF =>
v.load := '1'; v.load := '1';
v.flush := '1'; v.flush := '1';
@ -709,7 +713,8 @@ begin
v.mmu_op := '1'; v.mmu_op := '1';
when others => when others =>
end case; end case;
v.dc_req := l_in.valid and (v.load or v.store or v.sync 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 and
not hash_nop;
v.incomplete := v.dc_req and v.two_dwords; v.incomplete := v.dc_req and v.two_dwords;


-- Work out controls for load and store formatting -- Work out controls for load and store formatting

@ -183,6 +183,7 @@ architecture behaviour of soc is
signal alt_reset : std_ulogic; signal alt_reset : std_ulogic;
signal wb_syscon_in : wb_io_master_out; signal wb_syscon_in : wb_io_master_out;
signal wb_syscon_out : wb_io_slave_out; signal wb_syscon_out : wb_io_slave_out;
signal tb_ctrl : timebase_ctrl;


-- UART0 signals: -- UART0 signals:
signal wb_uart0_in : wb_io_master_out; signal wb_uart0_in : wb_io_master_out;
@ -271,8 +272,6 @@ architecture behaviour of soc is


signal core_run_out : std_ulogic_vector(NCPUS-1 downto 0); signal core_run_out : std_ulogic_vector(NCPUS-1 downto 0);


signal timebase : std_ulogic_vector(63 downto 0);

function wishbone_widen_data(wb : wb_io_master_out) return wishbone_master_out is function wishbone_widen_data(wb : wb_io_master_out) return wishbone_master_out is
variable wwb : wishbone_master_out; variable wwb : wishbone_master_out;
begin begin
@ -333,6 +332,7 @@ begin


-- either external reset, or from syscon -- either external reset, or from syscon
soc_reset <= rst or sw_soc_reset; soc_reset <= rst or sw_soc_reset;
tb_ctrl.reset <= soc_reset;


resets: process(system_clk) resets: process(system_clk)
begin begin
@ -352,21 +352,6 @@ begin
end if; end if;
end process; end process;


-- Timebase just increments at the system clock frequency.
-- There is currently no way to set it.
-- Ideally it would (appear to) run at 512MHz like IBM POWER systems,
-- but Linux seems to cope OK with it being 100MHz or whatever.
tbase: process(system_clk)
begin
if rising_edge(system_clk) then
if soc_reset = '1' then
timebase <= (others => '0');
else
timebase <= std_ulogic_vector(unsigned(timebase) + 1);
end if;
end if;
end process;

-- Processor cores -- Processor cores
processors: for i in 0 to NCPUS-1 generate processors: for i in 0 to NCPUS-1 generate
core: entity work.core core: entity work.core
@ -391,7 +376,7 @@ begin
rst => rst_core(i), rst => rst_core(i),
alt_reset => alt_reset_d, alt_reset => alt_reset_d,
run_out => core_run_out(i), run_out => core_run_out(i),
timebase => timebase, tb_ctrl => tb_ctrl,
wishbone_insn_in => wb_masters_in(i + NCPUS), wishbone_insn_in => wb_masters_in(i + NCPUS),
wishbone_insn_out => wb_masters_out(i + NCPUS), wishbone_insn_out => wb_masters_out(i + NCPUS),
wishbone_data_in => wb_masters_in(i), wishbone_data_in => wb_masters_in(i),
@ -823,7 +808,9 @@ begin
dram_at_0 => dram_at_0, dram_at_0 => dram_at_0,
core_reset => do_core_reset, core_reset => do_core_reset,
soc_reset => sw_soc_reset, soc_reset => sw_soc_reset,
alt_reset => alt_reset alt_reset => alt_reset,
tb_rdp => tb_ctrl.rd_prot,
tb_frz => tb_ctrl.freeze
); );


-- --

@ -36,7 +36,9 @@ entity syscon is
dram_at_0 : out std_ulogic; dram_at_0 : out std_ulogic;
core_reset : out std_ulogic_vector(NCPUS-1 downto 0); core_reset : out std_ulogic_vector(NCPUS-1 downto 0);
soc_reset : out std_ulogic; soc_reset : out std_ulogic;
alt_reset : out std_ulogic alt_reset : out std_ulogic;
tb_rdp : out std_ulogic;
tb_frz : out std_ulogic
); );
end entity syscon; end entity syscon;


@ -58,6 +60,7 @@ architecture behaviour of syscon is
constant SYS_REG_UART1_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001001"; constant SYS_REG_UART1_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001001";
constant SYS_REG_GIT_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001010"; constant SYS_REG_GIT_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001010";
constant SYS_REG_CPU_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001011"; constant SYS_REG_CPU_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001011";
constant SYS_REG_TB_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001100";


-- Muxed reg read signal -- Muxed reg read signal
signal reg_out : std_ulogic_vector(63 downto 0); signal reg_out : std_ulogic_vector(63 downto 0);
@ -119,6 +122,7 @@ architecture behaviour of syscon is
signal reg_uart1info : std_ulogic_vector(63 downto 0); signal reg_uart1info : std_ulogic_vector(63 downto 0);
signal reg_gitinfo : std_ulogic_vector(63 downto 0); signal reg_gitinfo : std_ulogic_vector(63 downto 0);
signal reg_cpuctrl : std_ulogic_vector(63 downto 0); signal reg_cpuctrl : std_ulogic_vector(63 downto 0);
signal reg_tbctrl : std_ulogic_vector(63 downto 0);
signal info_has_dram : std_ulogic; signal info_has_dram : std_ulogic;
signal info_has_bram : std_ulogic; signal info_has_bram : std_ulogic;
signal info_has_uart : std_ulogic; signal info_has_uart : std_ulogic;
@ -130,6 +134,8 @@ architecture behaviour of syscon is
signal info_fl_off : std_ulogic_vector(31 downto 0); signal info_fl_off : std_ulogic_vector(31 downto 0);
signal uinfo_16550 : std_ulogic; signal uinfo_16550 : std_ulogic;
signal uinfo_freq : std_ulogic_vector(31 downto 0); signal uinfo_freq : std_ulogic_vector(31 downto 0);
signal tb_rdprot : std_ulogic;
signal tb_freeze : std_ulogic;


-- Wishbone response latch -- Wishbone response latch
signal wb_rsp : wb_io_slave_out; signal wb_rsp : wb_io_slave_out;
@ -193,6 +199,8 @@ begin


reg_cpuctrl(63 downto 8) <= std_ulogic_vector(to_unsigned(NCPUS, 56)); reg_cpuctrl(63 downto 8) <= std_ulogic_vector(to_unsigned(NCPUS, 56));


reg_tbctrl <= 62x"0" & tb_rdprot & tb_freeze;

-- Wishbone response -- Wishbone response
wb_rsp.ack <= wishbone_in.cyc and wishbone_in.stb; wb_rsp.ack <= wishbone_in.cyc and wishbone_in.stb;
with wishbone_in.adr(SYS_REG_BITS downto 1) select reg_out <= with wishbone_in.adr(SYS_REG_BITS downto 1) select reg_out <=
@ -208,6 +216,7 @@ begin
reg_uart1info when SYS_REG_UART1_INFO, reg_uart1info when SYS_REG_UART1_INFO,
reg_gitinfo when SYS_REG_GIT_INFO, reg_gitinfo when SYS_REG_GIT_INFO,
reg_cpuctrl when SYS_REG_CPU_CTRL, reg_cpuctrl when SYS_REG_CPU_CTRL,
reg_tbctrl when SYS_REG_TB_CTRL,
(others => '0') when others; (others => '0') when others;
wb_rsp.dat <= reg_out(63 downto 32) when wishbone_in.adr(0) = '1' else wb_rsp.dat <= reg_out(63 downto 32) when wishbone_in.adr(0) = '1' else
reg_out(31 downto 0); reg_out(31 downto 0);
@ -222,17 +231,23 @@ begin
end if; end if;
end process; end process;


-- Timebase control
tb_rdp <= tb_rdprot;
tb_frz <= tb_freeze;

-- Initial state -- Initial state
ctrl_init_alt_reset <= '1' when HAS_DRAM else '0'; ctrl_init_alt_reset <= '1' when HAS_DRAM else '0';


-- Register writes -- Register writes
regs_write: process(clk) regs_write : process(clk)
begin begin
if rising_edge(clk) then if rising_edge(clk) then
if (rst) then if (rst) then
reg_ctrl <= (SYS_REG_CTRL_ALT_RESET => ctrl_init_alt_reset, reg_ctrl <= (SYS_REG_CTRL_ALT_RESET => ctrl_init_alt_reset,
others => '0'); others => '0');
reg_cpuctrl(7 downto 0) <= x"01"; -- enable cpu 0 only reg_cpuctrl(7 downto 0) <= x"01"; -- enable cpu 0 only
tb_rdprot <= '0';
tb_freeze <= '0';
else else
if wishbone_in.cyc and wishbone_in.stb and wishbone_in.we then if wishbone_in.cyc and wishbone_in.stb and wishbone_in.we then
-- Change this if CTRL ever has more than 32 bits -- Change this if CTRL ever has more than 32 bits
@ -245,6 +260,11 @@ begin
wishbone_in.adr(0) = '0' and wishbone_in.sel(0) = '1' then wishbone_in.adr(0) = '0' and wishbone_in.sel(0) = '1' then
reg_cpuctrl(7 downto 0) <= wishbone_in.dat(7 downto 0); reg_cpuctrl(7 downto 0) <= wishbone_in.dat(7 downto 0);
end if; end if;
if wishbone_in.adr(SYS_REG_BITS downto 1) = SYS_REG_TB_CTRL and
wishbone_in.adr(0) = '0' and wishbone_in.sel(0) = '1' then
tb_rdprot <= wishbone_in.dat(1);
tb_freeze <= wishbone_in.dat(0);
end if;
end if; end if;


-- Reset auto-clear -- Reset auto-clear

Loading…
Cancel
Save