From d112a7ad94dfd05861401fb66f5592137ba10c08 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 22 Sep 2023 08:56:31 +1000 Subject: [PATCH] Implement scv and rfscv The main quirk here is that scv sets LR and CTR instead of SRR0 and SRR1, and likewise rfscv uses LR and CTR. Also, scv uses a set of 128 interrupt vectors starting at 0x17000. Fortunately, the layout of the SPR RAM was already such that LR and CTR were in the even and odd halves respectively at the same index, so reading or writing LR and CTR instead of SRR0 and SRR1 is quite easy. Use of scv is subject to an FSCR bit but not an HFSCR bit. Signed-off-by: Paul Mackerras --- common.vhdl | 11 +++++++---- decode1.vhdl | 1 + decode2.vhdl | 6 +++++- decode_types.vhdl | 11 ++++++----- execute1.vhdl | 43 +++++++++++++++++++++++++++++++++---------- fetch1.vhdl | 2 +- predecode.vhdl | 1 + writeback.vhdl | 11 ++++++++++- 8 files changed, 64 insertions(+), 22 deletions(-) diff --git a/common.vhdl b/common.vhdl index 033b004..790d98c 100644 --- a/common.vhdl +++ b/common.vhdl @@ -260,6 +260,7 @@ package common is 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); @@ -272,7 +273,7 @@ package common is end record; constant ctrl_t_init : ctrl_t := (wait_state => '0', run => '1', xer_low => 18x"0", - fscr_ic => x"0", fscr_pref => '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', dscr => (others => '0'), others => (others => '0')); @@ -711,6 +712,7 @@ package common is 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); @@ -727,7 +729,7 @@ 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', hv_intr => '0', intr_vec => 0, + 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', @@ -816,13 +818,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; @@ -847,6 +849,7 @@ package common is type WritebackToExecute1Type is record intr : std_ulogic; hv_intr : std_ulogic; + scv_int : std_ulogic; srr1 : std_ulogic_vector(15 downto 0); end record; diff --git a/decode1.vhdl b/decode1.vhdl index 7fca54b..ccfdf9f 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -302,6 +302,7 @@ architecture behaviour of decode1 is 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), diff --git a/decode2.vhdl b/decode2.vhdl index b27f563..d094681 100644 --- a/decode2.vhdl +++ b/decode2.vhdl @@ -553,7 +553,11 @@ 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 => - if d_in.insn(9) = '0' then + 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; diff --git a/decode_types.vhdl b/decode_types.vhdl index 8cb732a..4f81a36 100644 --- a/decode_types.vhdl +++ b/decode_types.vhdl @@ -107,6 +107,7 @@ package decode_types is INSN_prtyw, INSN_prtyd, -- 70 INSN_rfid, + INSN_rfscv, INSN_rldic, INSN_rldicl, INSN_rldicr, @@ -114,8 +115,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, @@ -124,8 +125,8 @@ package decode_types is INSN_stdu, INSN_sthu, INSN_stwu, - INSN_subfic, - INSN_subfme, -- 90 + INSN_subfic, -- 90 + INSN_subfme, INSN_subfze, INSN_sync, INSN_tdi, @@ -135,7 +136,7 @@ package decode_types is INSN_xori, INSN_xoris, -- pad to 104 - INSN_063, INSN_064, INSN_065, INSN_066, INSN_067, + INSN_064, INSN_065, INSN_066, INSN_067, -- Non-prefixed instructions that have a MLS:D prefixed form and -- their corresponding prefixed instructions. diff --git a/execute1.vhdl b/execute1.vhdl index 7d714fb..dad8d72 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -96,6 +96,7 @@ architecture behaviour of execute1 is 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'); @@ -393,6 +394,7 @@ architecture behaviour of execute1 is 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; @@ -587,10 +589,12 @@ 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 - if interrupt_in.hv_intr = '0' then - wr_addr := RAMSPR_SRR0; - else + 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; @@ -1127,18 +1131,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 @@ -1230,6 +1236,9 @@ begin 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); @@ -1471,6 +1480,14 @@ begin 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 @@ -1536,6 +1553,7 @@ begin variable fv : Execute1ToFPUType; variable go : std_ulogic; variable bypass_valid : std_ulogic; + variable is_scv : std_ulogic; begin v := ex1; if busy_out = '0' then @@ -1670,6 +1688,7 @@ begin fv.valid := '1'; end if; end if; + is_scv := go and actions.se.scv_trap; if not HAS_FPU and ex1.div_in_progress = '1' then v.div_in_progress := not divider_to_x.valid; @@ -1710,6 +1729,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'; @@ -1970,6 +1990,7 @@ begin 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 @@ -2007,7 +2028,6 @@ begin 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'; @@ -2016,8 +2036,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; diff --git a/fetch1.vhdl b/fetch1.vhdl index 96c16fb..f07188d 100644 --- a/fetch1.vhdl +++ b/fetch1.vhdl @@ -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'; diff --git a/predecode.vhdl b/predecode.vhdl index 858910c..1846e3c 100644 --- a/predecode.vhdl +++ b/predecode.vhdl @@ -447,6 +447,7 @@ 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 diff --git a/writeback.vhdl b/writeback.vhdl index c479c20..d7690a5 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -73,6 +73,8 @@ begin 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; @@ -95,10 +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; @@ -108,6 +116,7 @@ begin 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 @@ -165,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;