From 6fe9dc964074f86d9406852d0e16f92eae72f7cc Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Aug 2022 19:38:16 +1000 Subject: [PATCH 1/6] dcache: Reduce metavalue warnings Among other changes, this makes the things that were previously declared as signals of integer base type to be unsigned, since unsigned can carry metavalues, and hence we can get the checking for metavalues closer to the uses and therefore restrict the checking to the situations where the signal really ought to be well defined. We now have a couple more signals that indicate request validity to help with that. Non-fatal asserts have been sprinkled throughout to assist with determining the cause of warnings from library functions (primarily NUMERIC_STD.TO_INTEGER and NUMERIC_STD."="). Signed-off-by: Paul Mackerras --- cache_ram.vhdl | 4 +- dcache.vhdl | 274 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 185 insertions(+), 93 deletions(-) diff --git a/cache_ram.vhdl b/cache_ram.vhdl index 641917f..66abefb 100644 --- a/cache_ram.vhdl +++ b/cache_ram.vhdl @@ -53,12 +53,14 @@ begin for i in 0 to WIDTH/BYTEWID-1 loop lbit := i * BYTEWID; mbit := lbit + BYTEWID - 1; - widx := to_integer(unsigned(wr_addr)); if wr_sel(i) = '1' then + assert not is_X(wr_addr); + widx := to_integer(unsigned(wr_addr)); ram(widx)(mbit downto lbit) <= wr_data(mbit downto lbit); end if; end loop; if rd_en = '1' then + assert not is_X(rd_addr); rd_data0 <= ram(to_integer(unsigned(rd_addr))); if TRACE then report "read a:" & to_hstring(rd_addr) & diff --git a/dcache.vhdl b/dcache.vhdl index 1e9fbcc..6f59fab 100644 --- a/dcache.vhdl +++ b/dcache.vhdl @@ -97,9 +97,9 @@ architecture rtl of dcache is -- .. |-----| | INDEX_BITS (5) -- .. --------| | TAG_BITS (45) - subtype row_t is integer range 0 to BRAM_ROWS-1; - subtype index_t is integer range 0 to NUM_LINES-1; - subtype way_t is integer range 0 to NUM_WAYS-1; + subtype row_t is unsigned(ROW_BITS-1 downto 0); + subtype index_t is unsigned(INDEX_BITS-1 downto 0); + subtype way_t is unsigned(WAY_BITS-1 downto 0); subtype row_in_line_t is unsigned(ROW_LINEBITS-1 downto 0); -- The cache data BRAM organized as described above for each way @@ -110,14 +110,14 @@ architecture rtl of dcache is -- memory. For now, work around it by putting all the tags subtype cache_tag_t is std_logic_vector(TAG_BITS-1 downto 0); -- type cache_tags_set_t is array(way_t) of cache_tag_t; --- type cache_tags_array_t is array(index_t) of cache_tags_set_t; +-- type cache_tags_array_t is array(0 to NUM_LINES-1) of cache_tags_set_t; constant TAG_RAM_WIDTH : natural := TAG_WIDTH * NUM_WAYS; subtype cache_tags_set_t is std_logic_vector(TAG_RAM_WIDTH-1 downto 0); - type cache_tags_array_t is array(index_t) of cache_tags_set_t; + type cache_tags_array_t is array(0 to NUM_LINES-1) of cache_tags_set_t; -- The cache valid bits subtype cache_way_valids_t is std_ulogic_vector(NUM_WAYS-1 downto 0); - type cache_valids_t is array(index_t) of cache_way_valids_t; + type cache_valids_t is array(0 to NUM_LINES-1) of cache_way_valids_t; type row_per_line_valid_t is array(0 to ROW_PER_LINE - 1) of std_ulogic; -- Storage. Hopefully implemented in LUTs @@ -137,7 +137,9 @@ architecture rtl of dcache is constant TLB_PTE_WAY_BITS : natural := TLB_NUM_WAYS * TLB_PTE_BITS; subtype tlb_way_t is integer range 0 to TLB_NUM_WAYS - 1; + subtype tlb_way_sig_t is unsigned(TLB_WAY_BITS-1 downto 0); subtype tlb_index_t is integer range 0 to TLB_SET_SIZE - 1; + subtype tlb_index_sig_t is unsigned(TLB_SET_BITS-1 downto 0); subtype tlb_way_valids_t is std_ulogic_vector(TLB_NUM_WAYS-1 downto 0); type tlb_valids_t is array(tlb_index_t) of tlb_way_valids_t; subtype tlb_tag_t is std_ulogic_vector(TLB_EA_TAG_BITS - 1 downto 0); @@ -312,8 +314,8 @@ architecture rtl of dcache is -- TLB hit state tlb_hit : std_ulogic; - tlb_hit_way : tlb_way_t; - tlb_hit_index : tlb_index_t; + tlb_hit_way : tlb_way_sig_t; + tlb_hit_index : tlb_index_sig_t; -- data buffer for data forwarded from writes to reads forward_data : std_ulogic_vector(63 downto 0); @@ -366,7 +368,6 @@ architecture rtl of dcache is -- Async signals on incoming request signal req_index : index_t; - signal req_row : row_t; signal req_hit_way : way_t; signal req_tag : cache_tag_t; signal req_op : op_t; @@ -375,6 +376,7 @@ architecture rtl of dcache is signal req_go : std_ulogic; signal early_req_row : row_t; + signal early_rd_valid : std_ulogic; signal cancel_store : std_ulogic; signal set_rsrv : std_ulogic; @@ -389,13 +391,13 @@ architecture rtl of dcache is signal use_forward2 : std_ulogic; -- Cache RAM interface - type cache_ram_out_t is array(way_t) of cache_row_t; + type cache_ram_out_t is array(0 to NUM_WAYS-1) of cache_row_t; signal cache_out : cache_ram_out_t; signal ram_wr_data : cache_row_t; signal ram_wr_select : std_ulogic_vector(ROW_SIZE - 1 downto 0); -- PLRU output interface - type plru_out_t is array(index_t) of std_ulogic_vector(WAY_BITS-1 downto 0); + type plru_out_t is array(0 to NUM_LINES-1) of std_ulogic_vector(WAY_BITS-1 downto 0); signal plru_victim : plru_out_t; signal replace_way : way_t; @@ -406,9 +408,10 @@ architecture rtl of dcache is signal tlb_tag_way : tlb_way_tags_t; signal tlb_pte_way : tlb_way_ptes_t; signal tlb_valid_way : tlb_way_valids_t; - signal tlb_req_index : tlb_index_t; + signal tlb_req_index : tlb_index_sig_t; + signal tlb_read_valid : std_ulogic; signal tlb_hit : std_ulogic; - signal tlb_hit_way : tlb_way_t; + signal tlb_hit_way : tlb_way_sig_t; signal pte : tlb_pte_t; signal ra : real_addr_t; signal valid_ra : std_ulogic; @@ -434,21 +437,19 @@ architecture rtl of dcache is -- Return the cache line index (tag index) for an address function get_index(addr: std_ulogic_vector) return index_t is begin - return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS))); + return unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS)); end; -- Return the cache row index (data memory) for an address function get_row(addr: std_ulogic_vector) return row_t is begin - return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS))); + return unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS)); end; -- Return the index of a row within a line function get_row_of_line(row: row_t) return row_in_line_t is - variable row_v : unsigned(ROW_BITS-1 downto 0); begin - row_v := to_unsigned(row, ROW_BITS); - return row_v(ROW_LINEBITS-1 downto 0); + return row(ROW_LINEBITS-1 downto 0); end; -- Returns whether this is the last row of a line @@ -485,10 +486,10 @@ architecture rtl of dcache is variable row_idx : std_ulogic_vector(ROW_LINEBITS-1 downto 0); variable result : std_ulogic_vector(ROW_BITS-1 downto 0); begin - row_v := std_ulogic_vector(to_unsigned(row, ROW_BITS)); + row_v := std_ulogic_vector(row); row_idx := row_v(ROW_LINEBITS-1 downto 0); row_v(ROW_LINEBITS-1 downto 0) := std_ulogic_vector(unsigned(row_idx) + 1); - return to_integer(unsigned(row_v)); + return unsigned(row_v); end; -- Get the tag value from the address @@ -498,7 +499,7 @@ architecture rtl of dcache is end; -- Read a tag from a tag memory row - function read_tag(way: way_t; tagset: cache_tags_set_t) return cache_tag_t is + function read_tag(way: integer; tagset: cache_tags_set_t) return cache_tag_t is begin return tagset(way * TAG_WIDTH + TAG_BITS - 1 downto way * TAG_WIDTH); end; @@ -586,6 +587,9 @@ begin r.mmu_req := '0'; r.d_valid := '0'; end if; + if r.req.valid = '1' and r.doall = '0' then + assert not is_X(r.req.addr) severity failure; + end if; if rst = '1' then r0_full <= '0'; elsif r1.full = '0' and d_in.hold = '0' then @@ -617,21 +621,30 @@ begin tlb_read : process(clk) variable index : tlb_index_t; variable addrbits : std_ulogic_vector(TLB_SET_BITS - 1 downto 0); + variable valid : std_ulogic; begin if rising_edge(clk) then if m_in.valid = '1' then addrbits := m_in.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 downto TLB_LG_PGSZ); + valid := not (m_in.tlbie and m_in.doall); else addrbits := d_in.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 downto TLB_LG_PGSZ); + valid := d_in.valid; end if; - index := to_integer(unsigned(addrbits)); -- If we have any op and the previous op isn't finished, -- then keep the same output for next cycle. - if r0_stall = '0' then + if r0_stall = '0' and valid = '1' then + assert not is_X(addrbits); + index := to_integer(unsigned(addrbits)); tlb_valid_way <= dtlb_valids(index); tlb_tag_way <= dtlb_tags(index); tlb_pte_way <= dtlb_ptes(index); end if; + if rst = '1' then + tlb_read_valid <= '0'; + elsif r0_stall = '0' then + tlb_read_valid <= valid; + end if; end if; end process; @@ -659,38 +672,39 @@ begin process(all) begin -- PLRU interface - if r1.tlb_hit_index = i then + if not is_X(r1.tlb_hit_index) and r1.tlb_hit_index = i then tlb_plru_acc_en <= r1.tlb_hit; + assert not is_X(r1.tlb_hit_way); else tlb_plru_acc_en <= '0'; end if; - tlb_plru_acc <= std_ulogic_vector(to_unsigned(r1.tlb_hit_way, TLB_WAY_BITS)); + tlb_plru_acc <= std_ulogic_vector(r1.tlb_hit_way); tlb_plru_victim(i) <= tlb_plru_out; end process; end generate; end generate; tlb_search : process(all) - variable hitway : tlb_way_t; + variable hitway : tlb_way_sig_t; variable hit : std_ulogic; variable eatag : tlb_tag_t; begin - tlb_req_index <= to_integer(unsigned(r0.req.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 - downto TLB_LG_PGSZ))); - hitway := 0; + tlb_req_index <= unsigned(r0.req.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 + downto TLB_LG_PGSZ)); + hitway := to_unsigned(0, TLB_WAY_BITS); hit := '0'; eatag := r0.req.addr(63 downto TLB_LG_PGSZ + TLB_SET_BITS); for i in tlb_way_t loop - if tlb_valid_way(i) = '1' and + if tlb_read_valid = '1' and tlb_valid_way(i) = '1' and read_tlb_tag(i, tlb_tag_way) = eatag then - hitway := i; + hitway := to_unsigned(i, TLB_WAY_BITS); hit := '1'; end if; end loop; tlb_hit <= hit and r0_valid; tlb_hit_way <= hitway; if tlb_hit = '1' then - pte <= read_tlb_pte(hitway, tlb_pte_way); + pte <= read_tlb_pte(to_integer(hitway), tlb_pte_way); else pte <= (others => '0'); end if; @@ -711,7 +725,7 @@ begin tlb_update : process(clk) variable tlbie : std_ulogic; variable tlbwe : std_ulogic; - variable repl_way : tlb_way_t; + variable repl_way : tlb_way_sig_t; variable eatag : tlb_tag_t; variable tagset : tlb_way_tags_t; variable pteset : tlb_way_ptes_t; @@ -727,22 +741,27 @@ begin end loop; elsif tlbie = '1' then if tlb_hit = '1' then - dtlb_valids(tlb_req_index)(tlb_hit_way) <= '0'; + assert not is_X(tlb_req_index); + assert not is_X(tlb_hit_way); + dtlb_valids(to_integer(tlb_req_index))(to_integer(tlb_hit_way)) <= '0'; end if; elsif tlbwe = '1' then + assert not is_X(tlb_req_index); if tlb_hit = '1' then repl_way := tlb_hit_way; else - repl_way := to_integer(unsigned(tlb_plru_victim(tlb_req_index))); + assert not is_X(tlb_plru_victim(to_integer(tlb_req_index))); + repl_way := unsigned(tlb_plru_victim(to_integer(tlb_req_index))); end if; + assert not is_X(repl_way); eatag := r0.req.addr(63 downto TLB_LG_PGSZ + TLB_SET_BITS); tagset := tlb_tag_way; - write_tlb_tag(repl_way, tagset, eatag); - dtlb_tags(tlb_req_index) <= tagset; + write_tlb_tag(to_integer(repl_way), tagset, eatag); + dtlb_tags(to_integer(tlb_req_index)) <= tagset; pteset := tlb_pte_way; - write_tlb_pte(repl_way, pteset, r0.req.data); - dtlb_ptes(tlb_req_index) <= pteset; - dtlb_valids(tlb_req_index)(repl_way) <= '1'; + write_tlb_pte(to_integer(repl_way), pteset, r0.req.data); + dtlb_ptes(to_integer(tlb_req_index)) <= pteset; + dtlb_valids(to_integer(tlb_req_index))(to_integer(repl_way)) <= '1'; end if; end if; end process; @@ -772,12 +791,12 @@ begin process(all) begin -- PLRU interface - if r1.hit_index = i then + if not is_X(r1.hit_index) and r1.hit_index = to_unsigned(i, INDEX_BITS) then plru_acc_en <= r1.cache_hit; else plru_acc_en <= '0'; end if; - plru_acc <= std_ulogic_vector(to_unsigned(r1.hit_way, WAY_BITS)); + plru_acc <= std_ulogic_vector(r1.hit_way); plru_victim(i) <= plru_out; end process; end generate; @@ -786,16 +805,24 @@ begin -- Cache tag RAM read port cache_tag_read : process(clk) variable index : index_t; + variable valid : std_ulogic; begin if rising_edge(clk) then if r0_stall = '1' then index := req_index; + valid := r0.req.valid and not (r0.tlbie or r0.tlbld); elsif m_in.valid = '1' then index := get_index(m_in.addr); + valid := not (m_in.tlbie or m_in.tlbld); else index := get_index(d_in.addr); + valid := d_in.valid; + end if; + if valid = '1' then + cache_tag_set <= cache_tags(to_integer(index)); + else + cache_tag_set <= (others => '0'); end if; - cache_tag_set <= cache_tags(index); end if; end process; @@ -804,20 +831,25 @@ begin variable addr : real_addr_t; begin if rising_edge(clk) then - addr := addr_to_real(wb_to_addr(snoop_in.adr)); - snoop_tag_set <= cache_tags(get_index(addr)); - snoop_wrtag <= get_tag(addr); - snoop_index <= get_index(addr); -- Don't snoop our own cycles snoop_valid <= '0'; if not (r1.wb.cyc = '1' and wishbone_in.stall = '0') then - snoop_valid <= snoop_in.cyc and snoop_in.stb and snoop_in.we; + 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; end if; end if; 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; @@ -836,17 +868,24 @@ begin variable fwd_match : std_ulogic; begin -- Extract line, row and tag from request - req_index <= get_index(r0.req.addr); - req_row <= get_row(r0.req.addr); + rindex := get_index(r0.req.addr); + req_index <= rindex; + req_row := get_row(r0.req.addr); req_tag <= get_tag(ra); go := r0_valid and not (r0.tlbie or r0.tlbld) and not r1.ls_error; + if is_X(r0.req.addr) then + go := '0'; + end if; + if go = '1' then + assert not is_X(r1.forward_tag); + end if; -- Test if pending request is a hit on any way -- In order to make timing in virtual mode, when we are using the TLB, -- we compare each way with each of the real addresses from each way of -- the TLB, and then decide later which match to use. - hit_way := 0; + hit_way := to_unsigned(0, WAY_BITS); is_hit := '0'; rel_match := '0'; fwd_match := '0'; @@ -854,47 +893,54 @@ begin rel_matches := (others => '0'); fwd_matches := (others => '0'); for j in tlb_way_t loop - hit_way_set(j) := 0; + hit_way_set(j) := to_unsigned(0, WAY_BITS); s_hit := '0'; s_pte := read_tlb_pte(j, tlb_pte_way); s_ra := s_pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) & r0.req.addr(TLB_LG_PGSZ - 1 downto 0); s_tag := get_tag(s_ra); - for i in way_t loop - if go = '1' and cache_valids(req_index)(i) = '1' and + if go = '1' then + assert not is_X(s_tag); + end if; + for i in 0 to NUM_WAYS-1 loop + if go = '1' and cache_valids(to_integer(rindex))(i) = '1' and read_tag(i, cache_tag_set) = s_tag and tlb_valid_way(j) = '1' then - hit_way_set(j) := i; + hit_way_set(j) := to_unsigned(i, WAY_BITS); s_hit := '1'; end if; end loop; hit_set(j) := s_hit; - if s_tag = r1.reload_tag then + if go = '1' and not is_X(r1.reload_tag) and s_tag = r1.reload_tag then rel_matches(j) := '1'; end if; - if s_tag = r1.forward_tag then + if go = '1' and s_tag = r1.forward_tag then fwd_matches(j) := '1'; end if; end loop; - if tlb_hit = '1' then - is_hit := hit_set(tlb_hit_way); - hit_way := hit_way_set(tlb_hit_way); - rel_match := rel_matches(tlb_hit_way); - fwd_match := fwd_matches(tlb_hit_way); + if tlb_hit = '1' and go = '1' then + assert not is_X(tlb_hit_way); + is_hit := hit_set(to_integer(tlb_hit_way)); + 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)); end if; else s_tag := get_tag(r0.req.addr); - for i in way_t loop - if go = '1' and cache_valids(req_index)(i) = '1' and + if go = '1' then + assert not is_X(s_tag); + end if; + for i in 0 to NUM_WAYS-1 loop + if go = '1' and cache_valids(to_integer(rindex))(i) = '1' and read_tag(i, cache_tag_set) = s_tag then - hit_way := i; + hit_way := to_unsigned(i, WAY_BITS); is_hit := '1'; end if; end loop; - if s_tag = r1.reload_tag then + if go = '1' and not is_X(r1.reload_tag) and s_tag = r1.reload_tag then rel_match := '1'; end if; - if s_tag = r1.forward_tag then + if go = '1' and s_tag = r1.forward_tag then fwd_match := '1'; end if; end if; @@ -904,7 +950,11 @@ begin -- Whether to use forwarded data for a load or not use_forward_st <= '0'; use_forward_rl <= '0'; - if r1.store_row = req_row and rel_match = '1' then + if rel_match = '1' then + assert not is_X(r1.store_row); + assert not is_X(req_row); + end if; + if rel_match = '1' and r1.store_row = req_row then -- Use the forwarding path if this cycle is a write to this row use_forward_st <= r1.write_bram; if r1.state = RELOAD_WAIT_ACK and wishbone_in.ack = '1' then @@ -912,27 +962,39 @@ begin end if; end if; use_forward2 <= '0'; - if r1.forward_row = req_row and fwd_match = '1' then + if fwd_match = '1' then + assert not is_X(r1.forward_row); + if is_X(req_row) then + report "req_row=" & to_hstring(req_row) & " addr=" & to_hstring(r0.req.addr) & " go=" & std_ulogic'image(go); + end if; + assert not is_X(req_row); + end if; + if fwd_match = '1' and r1.forward_row = req_row then use_forward2 <= r1.forward_valid; end if; -- The way to replace on a miss if r1.write_tag = '1' then - replace_way <= to_integer(unsigned(plru_victim(r1.store_index))); + assert not is_X(r1.store_index); + replace_way <= unsigned(plru_victim(to_integer(r1.store_index))); else replace_way <= r1.store_way; end if; -- See if the request matches the line currently being reloaded - if r1.state = RELOAD_WAIT_ACK and req_index = r1.store_index and - rel_match = '1' then + if r1.state = RELOAD_WAIT_ACK and rel_match = '1' then + assert not is_X(rindex); + assert not is_X(r1.store_index); + end if; + 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 -- but doesn't clear the valid bit on the line before refilling it. -- For a store, consider this a hit even if the row isn't valid -- 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(req_row mod ROW_PER_LINE) or + is_hit := not r0.req.load or r1.rows_valid(to_integer(req_row(ROW_LINEBITS-1 downto 0))) or use_forward_rl; hit_way := replace_way; end if; @@ -982,11 +1044,14 @@ begin if r0_stall = '0' then if m_in.valid = '1' then early_req_row <= get_row(m_in.addr); + early_rd_valid <= not (m_in.tlbie or m_in.tlbld); else early_req_row <= get_row(d_in.addr); + early_rd_valid <= d_in.valid and d_in.load; end if; else early_req_row <= req_row; + early_rd_valid <= r0.req.valid and r0.req.load; end if; end process; @@ -1145,8 +1210,8 @@ begin process(all) begin -- Cache hit reads - do_read <= '1'; - rd_addr <= std_ulogic_vector(to_unsigned(early_req_row, ROW_BITS)); + do_read <= early_rd_valid; + rd_addr <= std_ulogic_vector(early_req_row); cache_out(i) <= dout; -- Write mux: @@ -1156,13 +1221,15 @@ begin -- For timing, the mux on wr_data/sel/addr is not dependent on anything -- other than the current state. -- - wr_addr <= std_ulogic_vector(to_unsigned(r1.store_row, ROW_BITS)); + wr_addr <= std_ulogic_vector(r1.store_row); wr_sel_m <= (others => '0'); - if i = replace_way and - (r1.write_bram = '1' or - (r1.state = RELOAD_WAIT_ACK and wishbone_in.ack = '1')) then - wr_sel_m <= ram_wr_select; + if r1.write_bram = '1' or + (r1.state = RELOAD_WAIT_ACK and wishbone_in.ack = '1') then + assert not is_X(replace_way); + if to_unsigned(i, WAY_BITS) = replace_way then + wr_sel_m <= ram_wr_select; + end if; end if; end process; @@ -1182,9 +1249,9 @@ begin report "op:" & op_t'image(req_op) & " addr:" & to_hstring(r0.req.addr) & " nc:" & std_ulogic'image(r0.req.nc) & - " idx:" & integer'image(req_index) & + " idx:" & to_hstring(req_index) & " tag:" & to_hstring(req_tag) & - " way: " & integer'image(req_hit_way); + " way: " & to_hstring(req_hit_way); end if; if r0_valid = '1' then r1.mmu_req <= r0.mmu_req; @@ -1213,7 +1280,11 @@ begin when "10" => data_out(j + 7 downto j) := r1.forward_data(j + 7 downto j); when others => - data_out(j + 7 downto j) := cache_out(req_hit_way)(j + 7 downto j); + if is_X(req_hit_way) then + data_out(j + 7 downto j) := (others => 'X'); + else + data_out(j + 7 downto j) := cache_out(to_integer(req_hit_way))(j + 7 downto j); + end if; end case; end loop; r1.data_out <= data_out; @@ -1290,7 +1361,7 @@ begin -- On reset, clear all valid bits to force misses if rst = '1' then - for i in index_t loop + for i in 0 to NUM_LINES-1 loop cache_valids(i) <= (others => '0'); end loop; r1.state <= IDLE; @@ -1322,17 +1393,24 @@ begin end if; -- Do invalidations from snooped stores to memory - for i in way_t loop + if snoop_valid = '1' then + assert not is_X(snoop_tag_set); + assert not is_X(snoop_wrtag); + 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 - cache_valids(snoop_index)(i) <= '0'; + assert not is_X(snoop_index); + cache_valids(to_integer(snoop_index))(i) <= '0'; end if; end loop; if r1.write_tag = '1' then -- Store new tag in selected way + assert not is_X(r1.store_index); + assert not is_X(replace_way); for i in 0 to NUM_WAYS-1 loop - if i = replace_way then - cache_tags(r1.store_index)((i + 1) * TAG_WIDTH - 1 downto i * TAG_WIDTH) <= + if to_unsigned(i, WAY_BITS) = replace_way then + cache_tags(to_integer(r1.store_index))((i + 1) * TAG_WIDTH - 1 downto i * TAG_WIDTH) <= (TAG_WIDTH - 1 downto TAG_BITS => '0') & r1.reload_tag; end if; end loop; @@ -1408,7 +1486,7 @@ begin -- Normal load cache miss, start the reload machine -- report "cache miss real addr:" & to_hstring(req.real_addr) & - " idx:" & integer'image(get_index(req.real_addr)) & + " idx:" & to_hstring(get_index(req.real_addr)) & " tag:" & to_hstring(get_tag(req.real_addr)); -- Start the wishbone cycle @@ -1467,6 +1545,8 @@ begin -- If we are still sending requests, was one accepted ? if wishbone_in.stall = '0' and r1.wb.stb = '1' then -- That was the last word ? We are done sending. Clear stb. + assert not is_X(r1.wb.adr); + assert not is_X(r1.end_row_ix); if is_last_row_wb_addr(r1.wb.adr, r1.end_row_ix) then r1.wb.stb <= '0'; end if; @@ -1477,13 +1557,17 @@ begin -- Incoming acks processing if wishbone_in.ack = '1' then - r1.rows_valid(r1.store_row mod ROW_PER_LINE) <= '1'; + r1.rows_valid(to_integer(r1.store_row(ROW_LINEBITS-1 downto 0))) <= '1'; -- If this is the data we were looking for, we can -- complete the request next cycle. -- Compare the whole address in case the request in -- r1.req is not the one that started this refill. -- (Cases where req comes from r0 are handled as a load -- hit.) + if r1.full = '1' then + assert not is_X(r1.store_row); + 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.store_row = get_row(r1.req.real_addr) then @@ -1497,12 +1581,16 @@ begin end if; -- Check for completion + assert not is_X(r1.store_row); + assert not is_X(r1.end_row_ix); if is_last_row(r1.store_row, r1.end_row_ix) then -- Complete wishbone cycle r1.wb.cyc <= '0'; -- Cache line is now valid - cache_valids(r1.store_index)(r1.store_way) <= '1'; + assert not is_X(r1.store_index); + assert not is_X(r1.store_way); + cache_valids(to_integer(r1.store_index))(to_integer(r1.store_way)) <= '1'; ev.dcache_refill <= not r1.dcbz; r1.state <= IDLE; @@ -1533,6 +1621,7 @@ begin r1.wb.dat <= req.data; 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'; @@ -1556,6 +1645,7 @@ begin -- Got ack ? See if complete. if wishbone_in.ack = '1' then + assert not is_X(acks); if stbs_done and acks = 1 then r1.state <= IDLE; r1.wb.cyc <= '0'; @@ -1602,7 +1692,7 @@ begin d_out.valid & std_ulogic_vector(to_unsigned(op_t'pos(req_op), 3)) & stall_out & - std_ulogic_vector(to_unsigned(tlb_hit_way, 3)) & + std_ulogic_vector(resize(tlb_hit_way, 3)) & valid_ra & std_ulogic_vector(to_unsigned(state_t'pos(r1.state), 3)); end if; From 221a7b3df08df265aa718ab0b1c85ee1f497df1e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Aug 2022 19:42:35 +1000 Subject: [PATCH 2/6] icache: Reduce metavalue warnings As in dcache, this changes most signals declared with integer type to be unsigned bit vectors instead. Some code has been rearranged to do to_integer() or equality comparisons only when the relevant signals should be well defined. Non-fatal asserts have been sprinkled throughout to assist with determining the cause of warnings from library functions (primarily NUMERIC_STD.TO_INTEGER and NUMERIC_STD."="). Signed-off-by: Paul Mackerras --- icache.vhdl | 156 ++++++++++++++++++++++++++-------------------------- 1 file changed, 79 insertions(+), 77 deletions(-) diff --git a/icache.vhdl b/icache.vhdl index 58e2b5c..9113ae6 100644 --- a/icache.vhdl +++ b/icache.vhdl @@ -4,9 +4,7 @@ -- TODO (in no specific order): -- -- * Add debug interface to inspect cache content --- * Add snoop/invalidate path -- * Add multi-hit error detection --- * Pipelined bus interface (wb or axi) -- * Maybe add parity ? There's a few bits free in each BRAM row on Xilinx -- * Add optimization: service hits on partially loaded lines -- * Add optimization: (maybe) interrupt reload on fluch/redirect @@ -119,9 +117,11 @@ architecture rtl of icache is -- .. |-----| | INDEX_BITS (5) -- .. --------| | TAG_BITS (53) - subtype row_t is integer range 0 to BRAM_ROWS-1; + subtype row_t is unsigned(ROW_BITS-1 downto 0); subtype index_t is integer range 0 to NUM_LINES-1; + subtype index_sig_t is unsigned(INDEX_BITS-1 downto 0); subtype way_t is integer range 0 to NUM_WAYS-1; + subtype way_sig_t is unsigned(WAY_BITS-1 downto 0); subtype row_in_line_t is unsigned(ROW_LINEBITS-1 downto 0); -- We store a pre-decoded 10-bit insn_code along with the bottom 26 bits of @@ -187,7 +187,7 @@ architecture rtl of icache is type reg_internal_t is record -- Cache hit state (Latches for 1 cycle BRAM access) - hit_way : way_t; + hit_way : way_sig_t; hit_nia : std_ulogic_vector(63 downto 0); hit_smark : std_ulogic; hit_valid : std_ulogic; @@ -196,8 +196,8 @@ architecture rtl of icache is -- Cache miss state (reload state machine) state : state_t; wb : wishbone_master_out; - store_way : way_t; - store_index : index_t; + store_way : way_sig_t; + store_index : index_sig_t; recv_row : row_t; recv_valid : std_ulogic; store_row : row_t; @@ -215,9 +215,9 @@ architecture rtl of icache is signal ev : IcacheEventType; -- Async signals on incoming request - signal req_index : index_t; + signal req_index : index_sig_t; signal req_row : row_t; - signal req_hit_way : way_t; + signal req_hit_way : way_sig_t; signal req_tag : cache_tag_t; signal req_is_hit : std_ulogic; signal req_is_miss : std_ulogic; @@ -237,33 +237,30 @@ architecture rtl of icache is -- PLRU output interface type plru_out_t is array(index_t) of std_ulogic_vector(WAY_BITS-1 downto 0); signal plru_victim : plru_out_t; - signal replace_way : way_t; -- Memory write snoop signals signal snoop_valid : std_ulogic; - signal snoop_index : index_t; + signal snoop_index : index_sig_t; signal snoop_hits : cache_way_valids_t; signal log_insn : std_ulogic_vector(35 downto 0); -- Return the cache line index (tag index) for an address - function get_index(addr: std_ulogic_vector) return index_t is + function get_index(addr: std_ulogic_vector) return index_sig_t is begin - return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS))); + return unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS)); end; -- Return the cache row index (data memory) for an address function get_row(addr: std_ulogic_vector) return row_t is begin - return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS))); + return unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS)); end; -- Return the index of a row within a line function get_row_of_line(row: row_t) return row_in_line_t is - variable row_v : unsigned(ROW_BITS-1 downto 0); begin - row_v := to_unsigned(row, ROW_BITS); - return row_v(ROW_LINEBITS-1 downto 0); + return row(ROW_LINEBITS-1 downto 0); end; -- Returns whether this is the last row of a line @@ -298,13 +295,13 @@ architecture rtl of icache is -- function next_row(row: row_t) return row_t is variable row_v : std_ulogic_vector(ROW_BITS-1 downto 0); - variable row_idx : std_ulogic_vector(ROW_LINEBITS-1 downto 0); + variable row_idx : unsigned(ROW_LINEBITS-1 downto 0); variable result : std_ulogic_vector(ROW_BITS-1 downto 0); begin - row_v := std_ulogic_vector(to_unsigned(row, ROW_BITS)); - row_idx := row_v(ROW_LINEBITS-1 downto 0); - row_v(ROW_LINEBITS-1 downto 0) := std_ulogic_vector(unsigned(row_idx) + 1); - return to_integer(unsigned(row_v)); + row_v := std_ulogic_vector(row); + row_idx := row(ROW_LINEBITS-1 downto 0); + row_v(ROW_LINEBITS-1 downto 0) := std_ulogic_vector(row_idx + 1); + return unsigned(row_v); end; -- Read the instruction word for the given address in the current cache row @@ -312,6 +309,7 @@ architecture rtl of icache is data: cache_row_t) return std_ulogic_vector is variable word: integer range 0 to INSN_PER_ROW-1; begin + assert not is_X(addr) severity failure; word := to_integer(unsigned(addr(INSN_BITS+2-1 downto 2))); return data(word * ICWORDLEN + ICWORDLEN - 1 downto word * ICWORDLEN); end; @@ -436,12 +434,12 @@ begin begin do_read <= not stall_in; do_write <= '0'; - if r.recv_valid = '1' and r.store_way = i then + if r.recv_valid = '1' and r.store_way = to_unsigned(i, WAY_BITS) then do_write <= '1'; end if; cache_out(i) <= dout; - rd_addr <= std_ulogic_vector(to_unsigned(req_row, ROW_BITS)); - wr_addr <= std_ulogic_vector(to_unsigned(r.store_row, ROW_BITS)); + rd_addr <= std_ulogic_vector(req_row); + wr_addr <= std_ulogic_vector(r.store_row); wr_sel(0) <= do_write; end process; end generate; @@ -478,7 +476,7 @@ begin else plru_acc_en <= '0'; end if; - plru_acc <= std_ulogic_vector(to_unsigned(r.hit_way, WAY_BITS)); + plru_acc <= std_ulogic_vector(r.hit_way); plru_victim(i) <= plru_out; end process; end generate; @@ -550,15 +548,13 @@ begin -- Cache hit detection, output to fetch2 and other misc logic icache_comb : process(all) variable is_hit : std_ulogic; - variable hit_way : way_t; + variable hit_way : way_sig_t; variable insn : std_ulogic_vector(ICWORDLEN - 1 downto 0); variable icode : insn_code; begin -- Extract line, row and tag from request - if not is_X(i_in.nia) then - req_index <= get_index(i_in.nia); - req_row <= get_row(i_in.nia); - end if; + req_index <= get_index(i_in.nia); + req_row <= get_row(i_in.nia); req_tag <= get_tag(real_addr, i_in.big_endian); -- Calculate address of beginning of cache row, will be @@ -568,21 +564,20 @@ begin (ROW_OFF_BITS-1 downto 0 => '0'); -- Test if pending request is a hit on any way - hit_way := 0; + hit_way := to_unsigned(0, WAY_BITS); is_hit := '0'; + if i_in.req = '1' then + assert not is_X(req_index) and not is_X(req_row) severity failure; + end if; for i in way_t loop - if is_X(i_in.nia) then - -- FIXME: This is fragile - -- req_index or req_row could be a metavalue - is_hit := 'X'; - elsif i_in.req = '1' and - (cache_valids(req_index)(i) = '1' or + if i_in.req = '1' and + (cache_valids(to_integer(req_index))(i) = '1' or (r.state = WAIT_ACK and req_index = r.store_index and - i = r.store_way and - r.rows_valid(req_row mod ROW_PER_LINE) = '1')) then - if read_tag(i, cache_tags(req_index)) = req_tag then - hit_way := i; + to_unsigned(i, WAY_BITS) = r.store_way and + r.rows_valid(to_integer(req_row(ROW_LINEBITS-1 downto 0))) = '1')) then + if read_tag(i, cache_tags(to_integer(req_index))) = req_tag then + hit_way := to_unsigned(i, WAY_BITS); is_hit := '1'; end if; end if; @@ -598,13 +593,6 @@ begin end if; req_hit_way <= hit_way; - -- The way to replace on a miss - if r.state = CLR_TAG then - replace_way <= to_integer(unsigned(plru_victim(r.store_index))); - else - replace_way <= r.store_way; - end if; - -- Output instruction from current cache row -- -- Note: This is a mild violation of our design principle of having pipeline @@ -616,10 +604,13 @@ begin insn := (others => '0'); icode := INSN_illegal; if r.hit_valid = '1' then - insn := read_insn_word(r.hit_nia, cache_out(r.hit_way)); + assert not is_X(r.hit_way) severity failure; + insn := read_insn_word(r.hit_nia, cache_out(to_integer(r.hit_way))); -- Currently we use only the top bit for indicating illegal -- instructions because we know that insn_codes fit into 9 bits. - if insn(ICWORDLEN - 1) = '0' then + if is_X(insn) then + insn := (others => '0'); + elsif insn(ICWORDLEN - 1) = '0' then icode := insn_code'val(to_integer(unsigned(insn(ICWORDLEN-1 downto INSN_IMAGE_BITS)))); end if; end if; @@ -664,9 +655,9 @@ begin report "cache hit nia:" & to_hstring(i_in.nia) & " IR:" & std_ulogic'image(i_in.virt_mode) & " SM:" & std_ulogic'image(i_in.stop_mark) & - " idx:" & integer'image(req_index) & + " idx:" & to_hstring(req_index) & " tag:" & to_hstring(req_tag) & - " way:" & integer'image(req_hit_way) & + " way:" & to_hstring(req_hit_way) & " RA:" & to_hstring(real_addr); end if; end if; @@ -676,6 +667,9 @@ begin r.hit_nia <= i_in.nia; r.big_endian <= i_in.big_endian; end if; + if i_out.valid = '1' then + assert not is_X(i_out.insn) severity failure; + end if; end if; end process; @@ -686,7 +680,7 @@ begin variable snoop_addr : real_addr_t; variable snoop_tag : cache_tag_t; variable snoop_cache_tags : cache_tags_set_t; - variable replace_way : way_t; + variable replace_way : way_sig_t; begin if rising_edge(clk) then ev.icache_miss <= '0'; @@ -709,7 +703,7 @@ begin r.wb.adr <= (others => '0'); snoop_valid <= '0'; - snoop_index <= 0; + snoop_index <= to_unsigned(0, INDEX_BITS); snoop_hits <= (others => '0'); else -- Detect snooped writes and decode address into index and tag @@ -717,20 +711,22 @@ begin snoop_valid <= wb_snoop_in.cyc and wb_snoop_in.stb and wb_snoop_in.we; snoop_addr := addr_to_real(wb_to_addr(wb_snoop_in.adr)); snoop_index <= get_index(snoop_addr); - snoop_cache_tags := cache_tags(get_index(snoop_addr)); - if snoop_valid = '1' and is_X(snoop_addr) then - report "metavalue in snoop_addr" severity FAILURE; - end if; snoop_tag := get_tag(snoop_addr, '0'); snoop_hits <= (others => '0'); - for i in way_t loop - tag := read_tag(i, snoop_cache_tags); - -- Ignore endian bit in comparison - tag(TAG_BITS - 1) := '0'; - if tag = snoop_tag then - snoop_hits(i) <= '1'; + if snoop_valid = '1' then + if is_X(snoop_addr) then + report "metavalue in snoop_addr" severity FAILURE; end if; - end loop; + snoop_cache_tags := cache_tags(to_integer(get_index(snoop_addr))); + for i in way_t loop + tag := read_tag(i, snoop_cache_tags); + -- Ignore endian bit in comparison + tag(TAG_BITS - 1) := '0'; + if tag = snoop_tag then + snoop_hits(i) <= '1'; + end if; + end loop; + end if; -- Process cache invalidations if inval_in = '1' then @@ -742,8 +738,9 @@ begin -- Do invalidations from snooped stores to memory, one -- cycle after the address appears on wb_snoop_in. for i in way_t loop - if snoop_valid = '1' and snoop_hits(i) = '1' then - cache_valids(snoop_index)(i) <= '0'; + if snoop_hits(i) = '1' then + assert not is_X(snoop_index) severity failure; + cache_valids(to_integer(snoop_index))(i) <= '0'; end if; end loop; end if; @@ -761,7 +758,7 @@ begin report "cache miss nia:" & to_hstring(i_in.nia) & " IR:" & std_ulogic'image(i_in.virt_mode) & " SM:" & std_ulogic'image(i_in.stop_mark) & - " idx:" & integer'image(req_index) & + " idx:" & to_hstring(req_index) & " tag:" & to_hstring(req_tag) & " RA:" & to_hstring(real_addr); ev.icache_miss <= '1'; @@ -786,20 +783,24 @@ begin end if; when CLR_TAG | WAIT_ACK => + assert not is_X(r.store_index) severity failure; + assert not is_X(r.store_row) severity failure; + assert not is_X(r.recv_row) severity failure; if r.state = CLR_TAG then -- Get victim way from plru - replace_way := to_integer(unsigned(plru_victim(r.store_index))); + replace_way := unsigned(plru_victim(to_integer(r.store_index))); r.store_way <= replace_way; -- Force misses on that way while reloading that line - cache_valids(req_index)(replace_way) <= '0'; + assert not is_X(replace_way) severity failure; + cache_valids(to_integer(r.store_index))(to_integer(replace_way)) <= '0'; -- Store new tag in selected way for i in 0 to NUM_WAYS-1 loop - if i = replace_way then - tagset := cache_tags(r.store_index); + if to_unsigned(i, WAY_BITS) = replace_way then + tagset := cache_tags(to_integer(r.store_index)); write_tag(i, tagset, r.store_tag); - cache_tags(r.store_index) <= tagset; + cache_tags(to_integer(r.store_index)) <= tagset; end if; end loop; @@ -808,10 +809,11 @@ begin -- If we are writing in this cycle, mark row valid and see if we are done if r.recv_valid = '1' then - r.rows_valid(r.store_row mod ROW_PER_LINE) <= not inval_in; + r.rows_valid(to_integer(r.store_row(ROW_LINEBITS-1 downto 0))) <= not inval_in; if is_last_row(r.store_row, r.end_row_ix) then -- Cache line is now valid - cache_valids(r.store_index)(r.store_way) <= r.store_valid and not inval_in; + cache_valids(to_integer(r.store_index))(to_integer(r.store_way)) <= + r.store_valid and not inval_in; -- We are done r.state <= IDLE; end if; @@ -878,7 +880,7 @@ begin signal log_data : std_ulogic_vector(57 downto 0); begin data_log: process(clk) - variable lway: way_t; + variable lway: way_sig_t; variable wstate: std_ulogic; begin if rising_edge(clk) then @@ -897,7 +899,7 @@ begin r.fetch_failed & r.hit_nia(5 downto 2) & wstate & - std_ulogic_vector(to_unsigned(lway, 3)) & + std_ulogic_vector(resize(lway, 3)) & req_is_hit & req_is_miss & access_ok & ra_valid; From 4fcc2500c2ca8ea82080f3646ecec550d59663ae Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Aug 2022 19:46:09 +1000 Subject: [PATCH 3/6] core_debug: Reduce metavalue warnings Signed-off-by: Paul Mackerras --- core_debug.vhdl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core_debug.vhdl b/core_debug.vhdl index 592cf85..afebc7c 100644 --- a/core_debug.vhdl +++ b/core_debug.vhdl @@ -173,6 +173,7 @@ begin terminated <= '0'; log_trigger_delay <= 0; gspr_index <= (others => '0'); + log_dmi_addr <= (others => '0'); else if do_log_trigger = '1' or log_trigger_delay /= 0 then if log_trigger_delay = 255 or @@ -334,6 +335,7 @@ begin addr : std_ulogic_vector(31 downto 0)) return std_ulogic_vector is variable firstbit : integer; begin + assert not is_X(addr); firstbit := to_integer(unsigned(addr(1 downto 0))) * 64; return data(firstbit + 63 downto firstbit); end; @@ -351,9 +353,14 @@ begin begin if rising_edge(clk) then if log_wr_enable = '1' then + assert not is_X(log_wr_ptr); log_array(to_integer(log_wr_ptr)) <= log_data; end if; - log_rd <= log_array(to_integer(log_rd_ptr_latched)); + if is_X(log_rd_ptr_latched) then + log_rd <= (others => 'X'); + else + log_rd <= log_array(to_integer(log_rd_ptr_latched)); + end if; end if; end process; @@ -366,6 +373,7 @@ begin if rst = '1' then log_wr_ptr <= (others => '0'); log_toggle <= '0'; + log_rd_ptr_latched <= (others => '0'); elsif log_wr_enable = '1' then if log_wr_ptr = to_unsigned(LOG_LENGTH - 1, LOG_INDEX_BITS) then log_toggle <= not log_toggle; From a2d391dcaed019ba6633392aba217cef034cbed0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Aug 2022 19:46:45 +1000 Subject: [PATCH 4/6] decode2: Reduce metavalue warnings Explicitly check for undefined values and propagate them. Signed-off-by: Paul Mackerras --- decode2.vhdl | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/decode2.vhdl b/decode2.vhdl index 98557f9..f58bd9b 100644 --- a/decode2.vhdl +++ b/decode2.vhdl @@ -434,27 +434,37 @@ begin v.input_ov := '1'; -- need SO state if setting OV to 0 end if; when OP_MFSPR => - case decode_spr_num(d_in.insn) is - when SPR_XER => - v.input_ov := '1'; - when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR => - unit := LDST; - when others => - end case; + if is_X(d_in.insn) then + v.input_ov := 'X'; + else + case decode_spr_num(d_in.insn) is + when SPR_XER => + v.input_ov := '1'; + when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR => + unit := LDST; + when others => + end case; + end if; when OP_MTSPR => - case decode_spr_num(d_in.insn) is - when SPR_XER => - v.e.output_xer := '1'; - v.output_ov := '1'; - when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR => - unit := LDST; - if d_in.valid = '1' then - v.sgl_pipe := '1'; - end if; - when others => - end case; - if d_in.spr_info.valid = '1' and d_in.valid = '1' then - v.sgl_pipe := '1'; + if is_X(d_in.insn) then + v.e.output_xer := 'X'; + v.output_ov := 'X'; + v.sgl_pipe := 'X'; + else + case decode_spr_num(d_in.insn) is + when SPR_XER => + v.e.output_xer := '1'; + v.output_ov := '1'; + when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR => + unit := LDST; + if d_in.valid = '1' then + v.sgl_pipe := '1'; + end if; + when others => + end case; + if d_in.spr_info.valid = '1' and d_in.valid = '1' then + v.sgl_pipe := '1'; + end if; end if; when OP_CMP | OP_MCRXRX => v.input_ov := '1'; From 0279b923ba07bc55361daeb3b46148f3fd68db69 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Aug 2022 19:47:45 +1000 Subject: [PATCH 5/6] loadstore1: Reduce metavalue warnings Signed-off-by: Paul Mackerras --- loadstore1.vhdl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 7071582..01babc3 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -199,9 +199,14 @@ architecture behave of loadstore1 is return std_ulogic_vector is variable longsel : std_ulogic_vector(15 downto 0); begin - longsel := "00000000" & length_to_sel(size); - return std_ulogic_vector(shift_left(unsigned(longsel), - to_integer(unsigned(address)))); + if is_X(address) then + longsel := (others => 'X'); + return longsel; + else + longsel := "00000000" & length_to_sel(size); + return std_ulogic_vector(shift_left(unsigned(longsel), + to_integer(unsigned(address)))); + end if; end function xfer_data_sel; -- 23-bit right shifter for DP -> SP float conversions @@ -401,7 +406,7 @@ begin variable addr_mask : std_ulogic_vector(2 downto 0); begin v := request_init; - sprn := std_ulogic_vector(to_unsigned(decode_spr_num(l_in.insn), 10)); + sprn := l_in.insn(15 downto 11) & l_in.insn(20 downto 16); v.valid := l_in.valid; v.instr_tag := l_in.instr_tag; From 6fa468ca3d2291f2b8283e20911a0389f917c2ff Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Aug 2022 22:19:37 +1000 Subject: [PATCH 6/6] execute1: Reduce metavalue warnings Signed-off-by: Paul Mackerras --- execute1.vhdl | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/execute1.vhdl b/execute1.vhdl index 2d6af00..e31f4d6 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -863,11 +863,16 @@ begin else a_lt_lo := '0'; a_lt_hi := '0'; - if unsigned(a_in(30 downto 0)) < unsigned(b_in(30 downto 0)) then - a_lt_lo := '1'; - end if; - if unsigned(a_in(62 downto 31)) < unsigned(b_in(62 downto 31)) then - a_lt_hi := '1'; + if is_X(a_in) or is_X(b_in) then + a_lt_lo := 'X'; + a_lt_hi := 'X'; + else + if unsigned(a_in(30 downto 0)) < unsigned(b_in(30 downto 0)) then + a_lt_lo := '1'; + end if; + if unsigned(a_in(62 downto 31)) < unsigned(b_in(62 downto 31)) then + a_lt_hi := '1'; + end if; end if; if l = '1' then -- 64-bit comparison @@ -893,7 +898,6 @@ begin -- CR result mux bf := insn_bf(e_in.insn); - crnum := to_integer(unsigned(bf)); newcrf := (others => '0'); case e_in.sub_select is when "000" => @@ -908,8 +912,11 @@ begin when "010" => newcrf := ppc_cmpeqb(a_in, b_in); when "011" => - if e_in.insn(1) = '1' then + if is_X(e_in.insn) then + newcrf := (others => 'X'); + elsif e_in.insn(1) = '1' then -- CR logical instructions + crnum := to_integer(unsigned(bf)); j := (7 - crnum) * 4; newcrf := cr_in(j + 3 downto j); bt := insn_bt(e_in.insn); @@ -948,7 +955,8 @@ begin crnum := fxm_to_num(insn_fxm(e_in.insn)); write_cr_mask <= num_to_fxm(crnum); end if; - elsif e_in.output_cr = '1' then + elsif e_in.output_cr = '1' and not is_X(bf) then + crnum := to_integer(unsigned(bf)); write_cr_mask <= num_to_fxm(crnum); else write_cr_mask <= (others => '0');