From: Paul Mackerras Date: Thu, 4 Aug 2022 04:57:12 +0000 (+1000) Subject: predecode: Work around apparent yosys/nextpnr bug X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=30f65741350630b88a25fa43a3ee5ecfe5cdeb39;p=microwatt.git predecode: Work around apparent yosys/nextpnr bug This rearranges the synchronous process here to avoid setting fields of pred(i) to zero or INSN_illegal when valid_in is '0'. Experimentally, on ECP5 this acts like an asynchronous reset rather than a synchronous reset. Instead, handle possible indeterminate input for simulation by making the maj_predecode and row_predecode fields of predec_t be unsigned rather than insn_code (an enumerated type), and setting them to X when the input word is indeterminate. Signed-off-by: Paul Mackerras --- diff --git a/predecode.vhdl b/predecode.vhdl index 1e1d85b..3bbd224 100644 --- a/predecode.vhdl +++ b/predecode.vhdl @@ -454,26 +454,34 @@ architecture behaviour of predecoder is type predec_t is record image : std_ulogic_vector(31 downto 0); - maj_predecode : insn_code; - row_predecode : insn_code; + maj_predecode : unsigned(ICODE_LEN - 1 downto 0); + row_predecode : unsigned(ICODE_LEN - 1 downto 0); end record; subtype index_t is integer range 0 to WIDTH-1; type predec_array is array(index_t) of predec_t; signal pred : predec_array; + signal valid : std_ulogic; begin predecode_0: process(clk) variable majaddr : std_ulogic_vector(10 downto 0); variable rowaddr : std_ulogic_vector(10 downto 0); variable iword : std_ulogic_vector(31 downto 0); + variable majcode : insn_code; + variable rowcode : insn_code; begin if rising_edge(clk) then + valid <= valid_in; for i in index_t loop - if valid_in = '1' then - iword := insns_in(i * 32 + 31 downto i * 32); + iword := insns_in(i * 32 + 31 downto i * 32); + pred(i).image <= iword; + if is_X(iword) then + pred(i).maj_predecode <= (others => 'X'); + pred(i).row_predecode <= (others => 'X'); + else majaddr := iword(31 downto 26) & iword(4 downto 0); -- row_predecode_rom is used for op 19, 31, 59, 63 @@ -489,13 +497,10 @@ begin end if; rowaddr(2 downto 0) := iword(3 downto 1); - pred(i).image <= iword; - pred(i).maj_predecode <= major_predecode_rom(to_integer(unsigned(majaddr))); - pred(i).row_predecode <= row_predecode_rom(to_integer(unsigned(rowaddr))); - else - pred(i).image <= (others => '0'); - pred(i).maj_predecode <= INSN_illegal; - pred(i).row_predecode <= INSN_illegal; + majcode := major_predecode_rom(to_integer(unsigned(majaddr))); + pred(i).maj_predecode <= to_unsigned(insn_code'pos(majcode), ICODE_LEN); + rowcode := row_predecode_rom(to_integer(unsigned(rowaddr))); + pred(i).row_predecode <= to_unsigned(insn_code'pos(rowcode), ICODE_LEN); end if; end loop; end if; @@ -506,7 +511,7 @@ begin variable use_row : std_ulogic; variable illegal : std_ulogic; variable ici : std_ulogic_vector(IOUT_LEN - 1 downto 0); - variable icode : insn_code; + variable icode : unsigned(ICODE_LEN - 1 downto 0); begin for i in index_t loop iword := pred(i).image; @@ -532,7 +537,7 @@ begin when "011000" => -- 24 -- ori, special-case the standard NOP if std_match(iword, "01100000000000000000000000000000") then - icode := INSN_nop; + icode := to_unsigned(insn_code'pos(INSN_nop), ICODE_LEN); end if; when "011111" => -- 31 @@ -561,19 +566,20 @@ begin end if; -- Mark FP instructions as illegal if we don't have an FPU - if not HAS_FPU and icode >= INSN_first_frs then + if not HAS_FPU and not is_X(icode) and + to_integer(icode) >= insn_code'pos(INSN_first_frs) then illegal := '1'; end if; ici(31 downto 0) := iword; ici(IOUT_LEN - 1 downto 32) := (others => '0'); - if illegal = '1' or icode = INSN_illegal then + if valid = '0' or illegal = '1' or is_X(icode) or + icode = to_unsigned(insn_code'pos(INSN_illegal), ICODE_LEN) then -- Since an insn_code currently fits in 9 bits, use just -- the most significant bit of ici to indicate illegal insns. ici(IOUT_LEN - 1) := '1'; else - ici(IOUT_LEN - 1 downto IMAGE_LEN) := - std_ulogic_vector(to_unsigned(insn_code'pos(icode), ICODE_LEN)); + ici(IOUT_LEN - 1 downto IMAGE_LEN) := std_ulogic_vector(icode); end if; icodes_out(i * IOUT_LEN + IOUT_LEN - 1 downto i * IOUT_LEN) <= ici; end loop;