OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [rtl/] [core/] [neorv32_cpu_bus.vhd] - Diff between revs 39 and 40

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 39 Rev 40
Line 43... Line 43...
 
 
entity neorv32_cpu_bus is
entity neorv32_cpu_bus is
  generic (
  generic (
    CPU_EXTENSION_RISCV_C : boolean := true; -- implement compressed extension?
    CPU_EXTENSION_RISCV_C : boolean := true; -- implement compressed extension?
    -- Physical memory protection (PMP) --
    -- Physical memory protection (PMP) --
    PMP_USE               : boolean := false; -- implement physical memory protection?
    PMP_USE               : boolean := false -- implement physical memory protection?
    PMP_NUM_REGIONS       : natural := 4; -- number of regions (1..4)
 
    PMP_GRANULARITY       : natural := 16 -- granularity (1=8B, 2=16B, 3=32B, ...)
 
  );
  );
  port (
  port (
    -- global control --
    -- global control --
    clk_i          : in  std_ulogic; -- global clock, rising edge
    clk_i          : in  std_ulogic; -- global clock, rising edge
    rstn_i         : in  std_ulogic := '0'; -- global reset, low-active, async
    rstn_i         : in  std_ulogic := '0'; -- global reset, low-active, async
Line 108... Line 106...
  constant pmp_off_mode_c   : std_ulogic_vector(1 downto 0) := "00"; -- null region (disabled)
  constant pmp_off_mode_c   : std_ulogic_vector(1 downto 0) := "00"; -- null region (disabled)
--constant pmp_tor_mode_c   : std_ulogic_vector(1 downto 0) := "01"; -- top of range
--constant pmp_tor_mode_c   : std_ulogic_vector(1 downto 0) := "01"; -- top of range
--constant pmp_na4_mode_c   : std_ulogic_vector(1 downto 0) := "10"; -- naturally aligned four-byte region
--constant pmp_na4_mode_c   : std_ulogic_vector(1 downto 0) := "10"; -- naturally aligned four-byte region
  constant pmp_napot_mode_c : std_ulogic_vector(1 downto 0) := "11"; -- naturally aligned power-of-two region (>= 8 bytes)
  constant pmp_napot_mode_c : std_ulogic_vector(1 downto 0) := "11"; -- naturally aligned power-of-two region (>= 8 bytes)
 
 
 
  -- PMP granularity --
 
  constant pmp_g_c : natural := index_size_f(pmp_min_granularity_c);
 
 
  -- PMP configuration register bits --
  -- PMP configuration register bits --
  constant pmp_cfg_r_c  : natural := 0; -- read permit
  constant pmp_cfg_r_c  : natural := 0; -- read permit
  constant pmp_cfg_w_c  : natural := 1; -- write permit
  constant pmp_cfg_w_c  : natural := 1; -- write permit
  constant pmp_cfg_x_c  : natural := 2; -- execute permit
  constant pmp_cfg_x_c  : natural := 2; -- execute permit
  constant pmp_cfg_al_c : natural := 3; -- mode bit low
  constant pmp_cfg_al_c : natural := 3; -- mode bit low
Line 138... Line 139...
    timeout   : std_ulogic_vector(index_size_f(bus_timeout_c)-1 downto 0);
    timeout   : std_ulogic_vector(index_size_f(bus_timeout_c)-1 downto 0);
  end record;
  end record;
  signal i_arbiter, d_arbiter : bus_arbiter_t;
  signal i_arbiter, d_arbiter : bus_arbiter_t;
 
 
  -- physical memory protection --
  -- physical memory protection --
  type pmp_addr34_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(data_width_c+1 downto 0);
  type pmp_addr_t is array (0 to pmp_num_regions_c-1) of std_ulogic_vector(data_width_c-1 downto 0);
  type pmp_addr_t   is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(data_width_c-1 downto 0);
 
  type pmp_t is record
  type pmp_t is record
    addr_mask     : pmp_addr34_t; -- 34-bit physical address
    addr_mask     : pmp_addr_t;
    region_base   : pmp_addr_t; -- masked region base address for comparator
    region_base   : pmp_addr_t; -- region config base address
    region_i_addr : pmp_addr_t; -- masked instruction access base address for comparator
    region_i_addr : pmp_addr_t; -- masked instruction access base address for comparator
    region_d_addr : pmp_addr_t; -- masked data access base address for comparator
    region_d_addr : pmp_addr_t; -- masked data access base address for comparator
    i_match       : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region match for instruction interface
    i_match       : std_ulogic_vector(pmp_num_regions_c-1 downto 0); -- region match for instruction interface
    d_match       : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region match for data interface
    d_match       : std_ulogic_vector(pmp_num_regions_c-1 downto 0); -- region match for data interface
    if_fault      : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for fetch operation
    if_fault      : std_ulogic_vector(pmp_num_regions_c-1 downto 0); -- region access fault for fetch operation
    ld_fault      : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for load operation
    ld_fault      : std_ulogic_vector(pmp_num_regions_c-1 downto 0); -- region access fault for load operation
    st_fault      : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for store operation
    st_fault      : std_ulogic_vector(pmp_num_regions_c-1 downto 0); -- region access fault for store operation
  end record;
  end record;
  signal pmp : pmp_t;
  signal pmp : pmp_t;
 
 
  -- pmp faults anybody? --
  -- pmp faults anybody? --
  signal if_pmp_fault : std_ulogic; -- pmp instruction access fault
  signal if_pmp_fault : std_ulogic; -- pmp instruction access fault
Line 200... Line 200...
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  mem_do_reg: process(clk_i)
  mem_do_reg: process(clk_i)
  begin
  begin
    if rising_edge(clk_i) then
    if rising_edge(clk_i) then
      if (ctrl_i(ctrl_bus_mo_we_c) = '1') then
      if (ctrl_i(ctrl_bus_mo_we_c) = '1') then
        mdo <= wdata_i; -- memory data out register (MDO)
        mdo <= wdata_i; -- memory data output register (MDO)
      end if;
      end if;
    end if;
    end if;
  end process mem_do_reg;
  end process mem_do_reg;
 
 
  -- byte enable and output data alignment --
  -- byte enable and output data alignment --
Line 241... Line 241...
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  mem_out_buf: process(clk_i)
  mem_out_buf: process(clk_i)
  begin
  begin
    if rising_edge(clk_i) then
    if rising_edge(clk_i) then
      if (ctrl_i(ctrl_bus_mi_we_c) = '1') then
      if (ctrl_i(ctrl_bus_mi_we_c) = '1') then
        mdi <= d_bus_rdata; -- memory data in register (MDI)
        mdi <= d_bus_rdata; -- memory data input register (MDI)
      end if;
      end if;
    end if;
    end if;
  end process mem_out_buf;
  end process mem_out_buf;
 
 
  -- input data alignment and sign extension --
  -- input data alignment and sign extension --
Line 293... Line 293...
        d_arbiter.err_bus   <= '0';
        d_arbiter.err_bus   <= '0';
        d_arbiter.timeout   <= std_ulogic_vector(to_unsigned(bus_timeout_c, index_size_f(bus_timeout_c)));
        d_arbiter.timeout   <= std_ulogic_vector(to_unsigned(bus_timeout_c, index_size_f(bus_timeout_c)));
      else -- in progress
      else -- in progress
        d_arbiter.timeout   <= std_ulogic_vector(unsigned(d_arbiter.timeout) - 1);
        d_arbiter.timeout   <= std_ulogic_vector(unsigned(d_arbiter.timeout) - 1);
        d_arbiter.err_align <= (d_arbiter.err_align or d_misaligned)                                     and (not ctrl_i(ctrl_bus_derr_ack_c));
        d_arbiter.err_align <= (d_arbiter.err_align or d_misaligned)                                     and (not ctrl_i(ctrl_bus_derr_ack_c));
        d_arbiter.err_bus   <= (d_arbiter.err_bus   or (not or_all_f(d_arbiter.timeout)) or d_bus_err_i) and (not ctrl_i(ctrl_bus_derr_ack_c));
        d_arbiter.err_bus   <= (d_arbiter.err_bus   or (not or_all_f(d_arbiter.timeout)) or d_bus_err_i or
 
                                (st_pmp_fault and d_arbiter.wr_req) or (ld_pmp_fault and d_arbiter.rd_req)) and (not ctrl_i(ctrl_bus_derr_ack_c));
        if (d_bus_ack_i = '1') or (ctrl_i(ctrl_bus_derr_ack_c) = '1') then -- wait for normal termination / CPU abort
        if (d_bus_ack_i = '1') or (ctrl_i(ctrl_bus_derr_ack_c) = '1') then -- wait for normal termination / CPU abort
          d_arbiter.wr_req <= '0';
          d_arbiter.wr_req <= '0';
          d_arbiter.rd_req <= '0';
          d_arbiter.rd_req <= '0';
        end if;
        end if;
      end if;
      end if;
Line 344... Line 345...
        i_arbiter.err_bus   <= '0';
        i_arbiter.err_bus   <= '0';
        i_arbiter.timeout   <= std_ulogic_vector(to_unsigned(bus_timeout_c, index_size_f(bus_timeout_c)));
        i_arbiter.timeout   <= std_ulogic_vector(to_unsigned(bus_timeout_c, index_size_f(bus_timeout_c)));
      else -- in progress
      else -- in progress
        i_arbiter.timeout   <= std_ulogic_vector(unsigned(i_arbiter.timeout) - 1);
        i_arbiter.timeout   <= std_ulogic_vector(unsigned(i_arbiter.timeout) - 1);
        i_arbiter.err_align <= (i_arbiter.err_align or i_misaligned)                                     and (not ctrl_i(ctrl_bus_ierr_ack_c));
        i_arbiter.err_align <= (i_arbiter.err_align or i_misaligned)                                     and (not ctrl_i(ctrl_bus_ierr_ack_c));
        i_arbiter.err_bus   <= (i_arbiter.err_bus   or (not or_all_f(i_arbiter.timeout)) or i_bus_err_i) and (not ctrl_i(ctrl_bus_ierr_ack_c));
        i_arbiter.err_bus   <= (i_arbiter.err_bus   or (not or_all_f(i_arbiter.timeout)) or i_bus_err_i or if_pmp_fault) and (not ctrl_i(ctrl_bus_ierr_ack_c));
        if (i_bus_ack_i = '1') or (ctrl_i(ctrl_bus_ierr_ack_c) = '1') then -- wait for normal termination / CPU abort
        if (i_bus_ack_i = '1') or (ctrl_i(ctrl_bus_ierr_ack_c) = '1') then -- wait for normal termination / CPU abort
          i_arbiter.rd_req <= '0';
          i_arbiter.rd_req <= '0';
        end if;
        end if;
      end if;
      end if;
    end if;
    end if;
Line 366... Line 367...
  ma_instr_o <= i_arbiter.err_align;
  ma_instr_o <= i_arbiter.err_align;
  be_instr_o <= i_arbiter.err_bus;
  be_instr_o <= i_arbiter.err_bus;
 
 
  -- instruction bus (read-only) --
  -- instruction bus (read-only) --
  i_bus_addr_o  <= fetch_pc_i(data_width_c-1 downto 2) & "00"; -- instruction access is always 4-byte aligned (even for compressed instructions)
  i_bus_addr_o  <= fetch_pc_i(data_width_c-1 downto 2) & "00"; -- instruction access is always 4-byte aligned (even for compressed instructions)
  i_bus_wdata_o <= (others => '0');
  i_bus_wdata_o <= (others => '0'); -- instruction fetch is read-only
  i_bus_ben_o   <= (others => '0');
  i_bus_ben_o   <= (others => '0');
  i_bus_we_o    <= '0';
  i_bus_we_o    <= '0';
  i_bus_re_o    <= ctrl_i(ctrl_bus_if_c) and (not i_misaligned) and (not if_pmp_fault); -- no actual read when misaligned or PMP fault
  i_bus_re_o    <= ctrl_i(ctrl_bus_if_c) and (not i_misaligned) and (not if_pmp_fault); -- no actual read when misaligned or PMP fault
  i_bus_fence_o <= ctrl_i(ctrl_bus_fencei_c);
  i_bus_fence_o <= ctrl_i(ctrl_bus_fencei_c);
  instr_o       <= i_bus_rdata_i;
  instr_o       <= i_bus_rdata_i;
Line 382... Line 383...
                  '1' when (fetch_pc_i(1) = '1') else '0'; -- 32-bit accesses only
                  '1' when (fetch_pc_i(1) = '1') else '0'; -- 32-bit accesses only
 
 
 
 
  -- Physical Memory Protection (PMP) -------------------------------------------------------
  -- Physical Memory Protection (PMP) -------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- compute address masks --
  -- compute address masks (ITERATIVE!!!) --
  pmp_masks: process(clk_i)
  pmp_masks: process(clk_i)
  begin
  begin
    if rising_edge(clk_i) then -- address configuration (not the actual address check!) has a latency of +1 cycles
    if rising_edge(clk_i) then -- address mask computation (not the actual address check!) has a latency of max +32 cycles
      for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
      for r in 0 to pmp_num_regions_c-1 loop -- iterate over all regions
        pmp.addr_mask(r) <= (others => '0'); -- default
        pmp.addr_mask(r) <= (others => '0');
        for i in PMP_GRANULARITY+1 to 33 loop
        for i in pmp_g_c to data_width_c-1 loop
          if (i = PMP_GRANULARITY+1) then
          pmp.addr_mask(r)(i) <= pmp.addr_mask(r)(i-1) or (not pmp_addr_i(r)(i-1));
            pmp.addr_mask(r)(i) <= '0';
 
          else -- current bit = not AND(all previous bits)
 
            pmp.addr_mask(r)(i) <= not and_all_f(pmp_addr_i(r)(i-1 downto PMP_GRANULARITY));
 
          end if;
 
        end loop; -- i
        end loop; -- i
      end loop; -- r
      end loop; -- r
    end if;
    end if;
  end process pmp_masks;
  end process pmp_masks;
 
 
 
 
  -- compute operands for comparator --
  -- address access check --
  pmp_prepare_check:
  pmp_address_check:
  for r in 0 to PMP_NUM_REGIONS-1 generate -- iterate over all regions
  for r in 0 to pmp_num_regions_c-1 generate -- iterate over all regions
    -- ignore lowest 3 bits of access addresses -> minimal region size = 8 bytes
    pmp.region_i_addr(r) <= fetch_pc_i                             and pmp.addr_mask(r);
    pmp.region_i_addr(r) <= (fetch_pc_i(31 downto 3) & "000") and pmp.addr_mask(r)(33 downto 2);
    pmp.region_d_addr(r) <= mar                                    and pmp.addr_mask(r);
    pmp.region_d_addr(r) <= (mar(31 downto 3) & "000")        and pmp.addr_mask(r)(33 downto 2);
    pmp.region_base(r)   <= pmp_addr_i(r)(data_width_c+1 downto 2) and pmp.addr_mask(r);
    pmp.region_base(r)   <= pmp_addr_i(r)(33 downto 2)        and pmp.addr_mask(r)(33 downto 2);
    --
 
    pmp.i_match(r) <= '1' when (pmp.region_i_addr(r)(data_width_c-1 downto pmp_g_c) = pmp.region_base(r)(data_width_c-1 downto pmp_g_c)) else '0';
 
    pmp.d_match(r) <= '1' when (pmp.region_d_addr(r)(data_width_c-1 downto pmp_g_c) = pmp.region_base(r)(data_width_c-1 downto pmp_g_c)) else '0';
  end generate; -- r
  end generate; -- r
 
 
 
 
  -- check for access address match --
 
  pmp_addr_check: process (pmp)
 
  begin
 
    for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
 
      -- instruction interface --
 
      pmp.i_match(r) <= '0';
 
      if (pmp.region_i_addr(r)(31 downto PMP_GRANULARITY+2) = pmp.region_base(r)(31 downto PMP_GRANULARITY+2)) then
 
        pmp.i_match(r) <= '1';
 
      end if;
 
      -- data interface --
 
      pmp.d_match(r) <= '0';
 
      if (pmp.region_d_addr(r)(31 downto PMP_GRANULARITY+2) = pmp.region_base(r)(31 downto PMP_GRANULARITY+2)) then
 
        pmp.d_match(r) <= '1';
 
      end if;
 
    end loop; -- r
 
  end process pmp_addr_check;
 
 
 
 
 
  -- check access type and regions's permissions --
  -- check access type and regions's permissions --
  pmp_check_permission: process(pmp, pmp_ctrl_i, ctrl_i)
  pmp_check_permission: process(pmp, pmp_ctrl_i, ctrl_i)
  begin
  begin
    for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
    for r in 0 to pmp_num_regions_c-1 loop -- iterate over all regions
      if ((ctrl_i(ctrl_priv_lvl_msb_c downto ctrl_priv_lvl_lsb_c) = priv_mode_u_c) or (pmp_ctrl_i(r)(pmp_cfg_l_c) = '1')) and -- user privilege level or locked pmp entry -> enforce permissions also for machine mode
      if ((ctrl_i(ctrl_priv_lvl_msb_c downto ctrl_priv_lvl_lsb_c) = priv_mode_u_c) or (pmp_ctrl_i(r)(pmp_cfg_l_c) = '1')) and -- user privilege level or locked pmp entry -> enforce permissions also for machine mode
         (pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) /= pmp_off_mode_c) then -- active entry
         (pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) /= pmp_off_mode_c) then -- active entry
        pmp.if_fault(r) <= pmp.i_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_x_c)); -- fetch access match no execute permission
        pmp.if_fault(r) <= pmp.i_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_x_c)); -- fetch access match no execute permission
        pmp.ld_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_r_c)); -- load access match no read permission
        pmp.ld_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_r_c)); -- load access match no read permission
        pmp.st_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_w_c)); -- store access match no write permission
        pmp.st_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_w_c)); -- store access match no write permission

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.