mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-05-02 14:40:42 +00:00
Implement CTRL register
The CTRL register has a single bit called RUN. It has some unusual behaviours: - It can only be written via SPR number 152, which is privileged - It can only be read via SPR number 136, which is non-privileged - Reading in problem state (user mode) returns the RUN bit in bit 0, but reading in privileged state (hypervisor mode) returns the RUN bit in bits 0 and 15. - Reading SPR 152 in problem state causes a HEAI (illegal instruction) interrupt, but reading in privileged state is a no-op; this is the same as for an unimplemented SPR. The RUN bit goes to the PMU and is also plumbed out to drive a LED on the Arty board. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
@@ -58,6 +58,8 @@ package common is
|
|||||||
constant SPR_FSCR : spr_num_t := 153;
|
constant SPR_FSCR : spr_num_t := 153;
|
||||||
constant SPR_HFSCR : spr_num_t := 190;
|
constant SPR_HFSCR : spr_num_t := 190;
|
||||||
constant SPR_HEIR : spr_num_t := 339;
|
constant SPR_HEIR : spr_num_t := 339;
|
||||||
|
constant SPR_CTRL : spr_num_t := 136;
|
||||||
|
constant SPR_CTRLW : spr_num_t := 152;
|
||||||
|
|
||||||
-- PMU registers
|
-- PMU registers
|
||||||
constant SPR_UPMC1 : spr_num_t := 771;
|
constant SPR_UPMC1 : spr_num_t := 771;
|
||||||
@@ -148,6 +150,8 @@ package common is
|
|||||||
sel : spr_selector;
|
sel : spr_selector;
|
||||||
valid : std_ulogic;
|
valid : std_ulogic;
|
||||||
ispmu : std_ulogic;
|
ispmu : std_ulogic;
|
||||||
|
ronly : std_ulogic;
|
||||||
|
wonly : 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');
|
||||||
|
|
||||||
@@ -161,6 +165,7 @@ package common is
|
|||||||
constant SPRSEL_FSCR : spr_selector := 4x"7";
|
constant SPRSEL_FSCR : spr_selector := 4x"7";
|
||||||
constant SPRSEL_HFSCR : spr_selector := 4x"8";
|
constant SPRSEL_HFSCR : spr_selector := 4x"8";
|
||||||
constant SPRSEL_HEIR : spr_selector := 4x"9";
|
constant SPRSEL_HEIR : spr_selector := 4x"9";
|
||||||
|
constant SPRSEL_CTRL : spr_selector := 4x"a";
|
||||||
constant SPRSEL_XER : spr_selector := 4x"f";
|
constant SPRSEL_XER : spr_selector := 4x"f";
|
||||||
|
|
||||||
-- FSCR and HFSCR bit numbers
|
-- FSCR and HFSCR bit numbers
|
||||||
@@ -243,6 +248,7 @@ package common is
|
|||||||
|
|
||||||
-- This needs to die...
|
-- This needs to die...
|
||||||
type ctrl_t is record
|
type ctrl_t is record
|
||||||
|
run: std_ulogic;
|
||||||
tb: std_ulogic_vector(63 downto 0);
|
tb: std_ulogic_vector(63 downto 0);
|
||||||
dec: std_ulogic_vector(63 downto 0);
|
dec: std_ulogic_vector(63 downto 0);
|
||||||
msr: std_ulogic_vector(63 downto 0);
|
msr: std_ulogic_vector(63 downto 0);
|
||||||
@@ -258,7 +264,7 @@ package common is
|
|||||||
heir: std_ulogic_vector(63 downto 0);
|
heir: std_ulogic_vector(63 downto 0);
|
||||||
end record;
|
end record;
|
||||||
constant ctrl_t_init : ctrl_t :=
|
constant ctrl_t_init : ctrl_t :=
|
||||||
(xer_low => 18x"0",
|
(run => '1', xer_low => 18x"0",
|
||||||
fscr_ic => x"0", fscr_pref => '1', fscr_tar => '1',
|
fscr_ic => x"0", fscr_pref => '1', fscr_tar => '1',
|
||||||
hfscr_ic => x"0", hfscr_pref => '1', hfscr_tar => '1', hfscr_fp => '1',
|
hfscr_ic => x"0", hfscr_pref => '1', hfscr_tar => '1', hfscr_fp => '1',
|
||||||
others => (others => '0'));
|
others => (others => '0'));
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ entity core is
|
|||||||
|
|
||||||
ext_irq : in std_ulogic;
|
ext_irq : in std_ulogic;
|
||||||
|
|
||||||
|
run_out : out std_ulogic;
|
||||||
terminated_out : out std_logic
|
terminated_out : out std_logic
|
||||||
);
|
);
|
||||||
end core;
|
end core;
|
||||||
@@ -390,6 +391,7 @@ begin
|
|||||||
ls_events => loadstore_events,
|
ls_events => loadstore_events,
|
||||||
dc_events => dcache_events,
|
dc_events => dcache_events,
|
||||||
ic_events => icache_events,
|
ic_events => icache_events,
|
||||||
|
run_out => run_out,
|
||||||
terminate_out => terminate,
|
terminate_out => terminate,
|
||||||
dbg_spr_req => dbg_spr_req,
|
dbg_spr_req => dbg_spr_req,
|
||||||
dbg_spr_ack => dbg_spr_ack,
|
dbg_spr_ack => dbg_spr_ack,
|
||||||
|
|||||||
@@ -430,6 +430,8 @@ architecture behaviour of decode1 is
|
|||||||
i.sel := "0000";
|
i.sel := "0000";
|
||||||
i.valid := '1';
|
i.valid := '1';
|
||||||
i.ispmu := '0';
|
i.ispmu := '0';
|
||||||
|
i.ronly := '0';
|
||||||
|
i.wonly := '0';
|
||||||
case sprn is
|
case sprn is
|
||||||
when SPR_TB =>
|
when SPR_TB =>
|
||||||
i.sel := SPRSEL_TB;
|
i.sel := SPRSEL_TB;
|
||||||
@@ -458,6 +460,12 @@ architecture behaviour of decode1 is
|
|||||||
i.sel := SPRSEL_HFSCR;
|
i.sel := SPRSEL_HFSCR;
|
||||||
when SPR_HEIR =>
|
when SPR_HEIR =>
|
||||||
i.sel := SPRSEL_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 others =>
|
when others =>
|
||||||
i.valid := '0';
|
i.valid := '0';
|
||||||
end case;
|
end case;
|
||||||
|
|||||||
13
decode2.vhdl
13
decode2.vhdl
@@ -420,6 +420,8 @@ begin
|
|||||||
v.e.input_cr := d_in.decode.input_cr;
|
v.e.input_cr := d_in.decode.input_cr;
|
||||||
v.e.output_cr := d_in.decode.output_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
|
-- Work out whether XER SO/OV/OV32 bits are set
|
||||||
-- or used by this instruction
|
-- or used by this instruction
|
||||||
v.e.rc := decode_rc(d_in.decode.rc, d_in.insn);
|
v.e.rc := decode_rc(d_in.decode.rc, d_in.insn);
|
||||||
@@ -454,6 +456,9 @@ begin
|
|||||||
v.e.uses_tar := '1';
|
v.e.uses_tar := '1';
|
||||||
when others =>
|
when others =>
|
||||||
end case;
|
end case;
|
||||||
|
if d_in.spr_info.wonly = '1' then
|
||||||
|
v.e.spr_select.valid := '0';
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
when OP_MTSPR =>
|
when OP_MTSPR =>
|
||||||
if is_X(d_in.insn) then
|
if is_X(d_in.insn) then
|
||||||
@@ -474,7 +479,9 @@ begin
|
|||||||
v.e.uses_tar := '1';
|
v.e.uses_tar := '1';
|
||||||
when others =>
|
when others =>
|
||||||
end case;
|
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';
|
v.sgl_pipe := '1';
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
@@ -505,8 +512,6 @@ begin
|
|||||||
v.e.repeat := '1';
|
v.e.repeat := '1';
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
v.e.spr_select := d_in.spr_info;
|
|
||||||
|
|
||||||
if decctr = '1' then
|
if decctr = '1' then
|
||||||
-- read and write CTR
|
-- read and write CTR
|
||||||
v.e.ramspr_odd_rdaddr := RAMSPR_CTR;
|
v.e.ramspr_odd_rdaddr := RAMSPR_CTR;
|
||||||
@@ -602,7 +607,7 @@ 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' then
|
elsif d_in.spr_info.valid = '0' or d_in.spr_info.wonly = '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)
|
||||||
v.e.result_sel := "001"; -- logical_result
|
v.e.result_sel := "001"; -- logical_result
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ entity execute1 is
|
|||||||
|
|
||||||
dbg_ctrl_out : out ctrl_t;
|
dbg_ctrl_out : out ctrl_t;
|
||||||
|
|
||||||
|
run_out : out std_ulogic;
|
||||||
icache_inval : out std_ulogic;
|
icache_inval : out std_ulogic;
|
||||||
terminate_out : out std_ulogic;
|
terminate_out : out std_ulogic;
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ architecture behaviour of execute1 is
|
|||||||
write_hic : std_ulogic;
|
write_hic : std_ulogic;
|
||||||
write_heir : std_ulogic;
|
write_heir : std_ulogic;
|
||||||
set_heir : std_ulogic;
|
set_heir : std_ulogic;
|
||||||
|
write_ctrl : std_ulogic;
|
||||||
end record;
|
end record;
|
||||||
constant side_effect_init : side_effect_type := (others => '0');
|
constant side_effect_init : side_effect_type := (others => '0');
|
||||||
|
|
||||||
@@ -404,6 +406,15 @@ architecture behaviour of execute1 is
|
|||||||
return ret;
|
return ret;
|
||||||
end;
|
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
|
-- 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;
|
||||||
@@ -523,7 +534,7 @@ begin
|
|||||||
x_to_pmu.addr_v <= '0';
|
x_to_pmu.addr_v <= '0';
|
||||||
x_to_pmu.spr_num <= ex1.pmu_spr_num;
|
x_to_pmu.spr_num <= ex1.pmu_spr_num;
|
||||||
x_to_pmu.spr_val <= ex1.e.write_data;
|
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
|
-- 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
|
-- that are handled here, so for them we can just use the result most
|
||||||
@@ -1334,6 +1345,8 @@ begin
|
|||||||
v.se.write_hfscr := '1';
|
v.se.write_hfscr := '1';
|
||||||
when SPRSEL_HEIR =>
|
when SPRSEL_HEIR =>
|
||||||
v.se.write_heir := '1';
|
v.se.write_heir := '1';
|
||||||
|
when SPRSEL_CTRL =>
|
||||||
|
v.se.write_ctrl := '1';
|
||||||
when others =>
|
when others =>
|
||||||
end case;
|
end case;
|
||||||
end if;
|
end if;
|
||||||
@@ -1773,6 +1786,7 @@ begin
|
|||||||
assemble_fscr(ctrl) when SPRSEL_FSCR,
|
assemble_fscr(ctrl) when SPRSEL_FSCR,
|
||||||
assemble_hfscr(ctrl) when SPRSEL_HFSCR,
|
assemble_hfscr(ctrl) when SPRSEL_HFSCR,
|
||||||
ctrl.heir when SPRSEL_HEIR,
|
ctrl.heir when SPRSEL_HEIR,
|
||||||
|
assemble_ctrl(ctrl, ex1.msr(MSR_PR)) when SPRSEL_CTRL,
|
||||||
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;
|
||||||
@@ -1943,6 +1957,9 @@ begin
|
|||||||
ctrl_tmp.heir(63 downto 32) <= (others => '0');
|
ctrl_tmp.heir(63 downto 32) <= (others => '0');
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
|
if ex1.se.write_ctrl = '1' then
|
||||||
|
ctrl_tmp.run <= ex1.e.write_data(0);
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
if interrupt_in.intr = '1' then
|
if interrupt_in.intr = '1' then
|
||||||
@@ -1981,6 +1998,7 @@ begin
|
|||||||
e_out <= ex2.e;
|
e_out <= ex2.e;
|
||||||
e_out.msr <= msr_copy(ctrl.msr);
|
e_out.msr <= msr_copy(ctrl.msr);
|
||||||
|
|
||||||
|
run_out <= ctrl.run;
|
||||||
terminate_out <= ex2.se.terminate;
|
terminate_out <= ex2.se.terminate;
|
||||||
icache_inval <= ex2.se.icache_inval;
|
icache_inval <= ex2.se.icache_inval;
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,9 @@ end entity toplevel;
|
|||||||
|
|
||||||
architecture behaviour of toplevel is
|
architecture behaviour of toplevel is
|
||||||
|
|
||||||
|
-- Status
|
||||||
|
signal run_out : std_ulogic;
|
||||||
|
|
||||||
-- Reset signals:
|
-- Reset signals:
|
||||||
signal soc_rst : std_ulogic;
|
signal soc_rst : std_ulogic;
|
||||||
signal pll_rst : std_ulogic;
|
signal pll_rst : std_ulogic;
|
||||||
@@ -263,6 +266,7 @@ begin
|
|||||||
system_clk => system_clk,
|
system_clk => system_clk,
|
||||||
rst => soc_rst,
|
rst => soc_rst,
|
||||||
sw_soc_reset => sw_rst,
|
sw_soc_reset => sw_rst,
|
||||||
|
run_out => run_out,
|
||||||
|
|
||||||
-- UART signals
|
-- UART signals
|
||||||
uart0_txd => uart_main_tx,
|
uart0_txd => uart_main_tx,
|
||||||
@@ -742,6 +746,7 @@ begin
|
|||||||
led4 <= system_clk_locked;
|
led4 <= system_clk_locked;
|
||||||
led5 <= eth_clk_locked;
|
led5 <= eth_clk_locked;
|
||||||
led6 <= not soc_rst;
|
led6 <= not soc_rst;
|
||||||
|
led7 <= run_out;
|
||||||
|
|
||||||
-- GPIO
|
-- GPIO
|
||||||
gpio_in(10) <= btn0;
|
gpio_in(10) <= btn0;
|
||||||
|
|||||||
3
soc.vhdl
3
soc.vhdl
@@ -99,6 +99,8 @@ entity soc is
|
|||||||
rst : in std_ulogic;
|
rst : in std_ulogic;
|
||||||
system_clk : in std_ulogic;
|
system_clk : in std_ulogic;
|
||||||
|
|
||||||
|
run_out : out std_ulogic;
|
||||||
|
|
||||||
-- "Large" (64-bit) DRAM wishbone
|
-- "Large" (64-bit) DRAM wishbone
|
||||||
wb_dram_in : out wishbone_master_out;
|
wb_dram_in : out wishbone_master_out;
|
||||||
wb_dram_out : in wishbone_slave_out := wishbone_slave_out_init;
|
wb_dram_out : in wishbone_slave_out := wishbone_slave_out_init;
|
||||||
@@ -366,6 +368,7 @@ begin
|
|||||||
clk => system_clk,
|
clk => system_clk,
|
||||||
rst => rst_core,
|
rst => rst_core,
|
||||||
alt_reset => alt_reset_d,
|
alt_reset => alt_reset_d,
|
||||||
|
run_out => run_out,
|
||||||
wishbone_insn_in => wishbone_icore_in,
|
wishbone_insn_in => wishbone_icore_in,
|
||||||
wishbone_insn_out => wishbone_icore_out,
|
wishbone_insn_out => wishbone_icore_out,
|
||||||
wishbone_data_in => wishbone_dcore_in,
|
wishbone_data_in => wishbone_dcore_in,
|
||||||
|
|||||||
Reference in New Issue
Block a user