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

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.6/] [rtl/] [w11a/] [pdp11_cache.vhd] - Rev 24

Compare with Previous | Blame | View Log

-- $Id: pdp11_cache.vhd 427 2011-11-19 21:04:11Z mueller $
--
-- Copyright 2008-2011 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
--
-- This program is free software; you may redistribute and/or modify it under
-- the terms of the GNU General Public License as published by the Free
-- Software Foundation, either version 2, or at your option any later version.
--
-- This program is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-- for complete details.
-- 
------------------------------------------------------------------------------
-- Module Name:    pdp11_cache - syn
-- Description:    pdp11: cache
--
-- Dependencies:   memlib/ram_2swsr_rfirst_gen
-- Test bench:     -
-- Target Devices: generic
-- Tool versions:  xst 8.2, 9.1, 9.2, 13.1; ghdl 0.18-0.29
-- Revision History: 
-- Date         Rev Version  Comment
-- 2011-11-18   427   1.0.3  now numeric_std clean
-- 2008-02-23   118   1.0.2  ce cache in s_idle to avoid U's in sim
--                           factor invariants out of if's; fix tag rmiss logic
-- 2008-02-17   117   1.0.1  use em_(mreq|sres) interface; use req,we for mem
--                           recode, ghdl doesn't like partial vector port maps
-- 2008-02-16   116   1.0    Initial version 
------------------------------------------------------------------------------
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
use work.slvtypes.all;
use work.memlib.all;
use work.pdp11.all;
 
entity pdp11_cache is                   -- cache
  port (
    CLK : in slbit;                     -- clock
    GRESET : in slbit;                  -- global reset
    EM_MREQ : in em_mreq_type;          -- em request
    EM_SRES : out em_sres_type;         -- em response
    FMISS : in slbit;                   -- force miss
    CHIT : out slbit;                   -- cache hit flag
    MEM_REQ : out slbit;                -- memory: request
    MEM_WE : out slbit;                 -- memory: write enable
    MEM_BUSY : in slbit;                -- memory: controller busy
    MEM_ACK_R : in slbit;               -- memory: acknowledge read
    MEM_ADDR : out slv20;               -- memory: address
    MEM_BE : out slv4;                  -- memory: byte enable
    MEM_DI : out slv32;                 -- memory: data in  (memory view)
    MEM_DO : in slv32                   -- memory: data out (memory view)
  );
end pdp11_cache;
 
 
architecture syn of pdp11_cache is
 
  type state_type is (
    s_idle,                             -- s_idle: wait for req
    s_read,                             -- s_read: read cycle
    s_rmiss,                            -- s_rmiss: read miss
    s_write                             -- s_write: write cycle
  );
 
  type regs_type is record
    state : state_type;                 -- state
    addr_w : slbit;                     -- address - word select
    addr_l : slv11;                     -- address - cache line address
    addr_t : slv9;                      -- address - cache tag part
    be : slv4;                          -- byte enables (at 4 byte level)
    di : slv16;                         -- data
  end record regs_type;
 
  constant regs_init : regs_type := (
    s_idle,                             -- state
    '0',                                -- addr_w
    (others=>'0'),                      -- addr_l
    (others=>'0'),                      -- addr_t
    (others=>'0'),                      -- be
    (others=>'0')                       -- di
  );
 
  signal R_REGS : regs_type := regs_init;  -- state registers
  signal N_REGS : regs_type := regs_init;  -- next value state regs
 
  signal CMEM_TAG_CEA  : slbit := '0';
  signal CMEM_TAG_CEB  : slbit := '0';
  signal CMEM_TAG_WEA  : slbit := '0';
  signal CMEM_TAG_WEB  : slbit := '0';
  signal CMEM_TAG_DIB  : slv9  := (others=>'0');
  signal CMEM_TAG_DOA  : slv9  := (others=>'0');
  signal CMEM_DAT_CEA  : slbit := '0';
  signal CMEM_DAT_CEB  : slbit := '0';
  signal CMEM_DAT_WEA  : slv4 := "0000";
  signal CMEM_DAT_WEB  : slv4 := "0000";
  signal CMEM_DIA_0    : slv9 := (others=>'0');
  signal CMEM_DIA_1    : slv9 := (others=>'0');
  signal CMEM_DIA_2    : slv9 := (others=>'0');
  signal CMEM_DIA_3    : slv9 := (others=>'0');
  signal CMEM_DIB_0    : slv9 := (others=>'0');
  signal CMEM_DIB_1    : slv9 := (others=>'0');
  signal CMEM_DIB_2    : slv9 := (others=>'0');
  signal CMEM_DIB_3    : slv9 := (others=>'0');
  signal CMEM_DOA_0    : slv9 := (others=>'0');
  signal CMEM_DOA_1    : slv9 := (others=>'0');
  signal CMEM_DOA_2    : slv9 := (others=>'0');
  signal CMEM_DOA_3    : slv9 := (others=>'0');
 
begin
 
  CMEM_TAG : ram_2swsr_rfirst_gen
    generic map (
      AWIDTH => 11,
      DWIDTH =>  9)
    port map (
      CLKA  => CLK,
      CLKB  => CLK,
      ENA   => CMEM_TAG_CEA,
      ENB   => CMEM_TAG_CEB,
      WEA   => CMEM_TAG_WEA,
      WEB   => CMEM_TAG_WEB,
      ADDRA => EM_MREQ.addr(12 downto 2),
      ADDRB => R_REGS.addr_l,
      DIA   => EM_MREQ.addr(21 downto 13),
      DIB   => CMEM_TAG_DIB,
      DOA   => CMEM_TAG_DOA,
      DOB   => open
      );
 
  CMEM_DAT0 : ram_2swsr_rfirst_gen
    generic map (
      AWIDTH => 11,
      DWIDTH =>  9)
    port map (
      CLKA  => CLK,
      CLKB  => CLK,
      ENA   => CMEM_DAT_CEA,
      ENB   => CMEM_DAT_CEB,
      WEA   => CMEM_DAT_WEA(0),
      WEB   => CMEM_DAT_WEB(0),
      ADDRA => EM_MREQ.addr(12 downto 2),
      ADDRB => R_REGS.addr_l,
      DIA   => CMEM_DIA_0,
      DIB   => CMEM_DIB_0,
      DOA   => CMEM_DOA_0,
      DOB   => open
      );
 
  CMEM_DAT1 : ram_2swsr_rfirst_gen
    generic map (
      AWIDTH => 11,
      DWIDTH =>  9)
    port map (
      CLKA  => CLK,
      CLKB  => CLK,
      ENA   => CMEM_DAT_CEA,
      ENB   => CMEM_DAT_CEB,
      WEA   => CMEM_DAT_WEA(1),
      WEB   => CMEM_DAT_WEB(1),
      ADDRA => EM_MREQ.addr(12 downto 2),
      ADDRB => R_REGS.addr_l,
      DIA   => CMEM_DIA_1,
      DIB   => CMEM_DIB_1,
      DOA   => CMEM_DOA_1,
      DOB   => open
      );
 
  CMEM_DAT2 : ram_2swsr_rfirst_gen
    generic map (
      AWIDTH => 11,
      DWIDTH =>  9)
    port map (
      CLKA  => CLK,
      CLKB  => CLK,
      ENA   => CMEM_DAT_CEA,
      ENB   => CMEM_DAT_CEB,
      WEA   => CMEM_DAT_WEA(2),
      WEB   => CMEM_DAT_WEB(2),
      ADDRA => EM_MREQ.addr(12 downto 2),
      ADDRB => R_REGS.addr_l,
      DIA   => CMEM_DIA_2,
      DIB   => CMEM_DIB_2,
      DOA   => CMEM_DOA_2,
      DOB   => open
      );
 
  CMEM_DAT3 : ram_2swsr_rfirst_gen
    generic map (
      AWIDTH => 11,
      DWIDTH =>  9)
    port map (
      CLKA  => CLK,
      CLKB  => CLK,
      ENA   => CMEM_DAT_CEA,
      ENB   => CMEM_DAT_CEB,
      WEA   => CMEM_DAT_WEA(3),
      WEB   => CMEM_DAT_WEB(3),
      ADDRA => EM_MREQ.addr(12 downto 2),
      ADDRB => R_REGS.addr_l,
      DIA   => CMEM_DIA_3,
      DIB   => CMEM_DIB_3,
      DOA   => CMEM_DOA_3,
      DOB   => open
      );
 
  proc_regs: process (CLK)
  begin
 
    if rising_edge(CLK) then
      if GRESET = '1' then
        R_REGS <= regs_init;
      else
        R_REGS <= N_REGS;
      end if;
    end if;
 
  end process proc_regs;
 
  proc_next: process (R_REGS, EM_MREQ, FMISS,
                      CMEM_TAG_DOA,
                      CMEM_DOA_0, CMEM_DOA_1, CMEM_DOA_2, CMEM_DOA_3, 
                      MEM_BUSY, MEM_ACK_R, MEM_DO)
 
    variable r : regs_type := regs_init;
    variable n : regs_type := regs_init;
 
    variable iaddr_w : slbit := '0';
    variable iaddr_l : slv11 := (others=>'0');
    variable iaddr_t : slv9  := (others=>'0');
 
    variable itagok : slbit := '0';
    variable ivalok : slbit := '0';
 
    variable icmem_tag_cea : slbit := '0';
    variable icmem_tag_ceb : slbit := '0';
    variable icmem_tag_wea : slbit := '0';
    variable icmem_tag_web : slbit := '0';
    variable icmem_tag_dib : slv9  := (others=>'0');
    variable icmem_dat_cea : slbit := '0';
    variable icmem_dat_ceb : slbit := '0';
    variable icmem_dat_wea : slv4  := "0000";
    variable icmem_dat_web : slv4  := "0000";
    variable icmem_val_doa : slv4  := "0000";
    variable icmem_dat_doa : slv32 := (others=>'0');
    variable icmem_val_dib : slv4  := "0000";
    variable icmem_dat_dib : slv32 := (others=>'0');
 
    variable iackr : slbit := '0';
    variable iackw : slbit := '0';
    variable ichit : slbit := '0';
    variable iosel : slv2  := "11";
 
    variable imem_reqr : slbit := '0';
    variable imem_reqw : slbit := '0';
    variable imem_be   : slv4  := "0000";
 
  begin
 
    r := R_REGS;
    n := R_REGS;
 
    iaddr_w := EM_MREQ.addr(1);                -- get word select
    iaddr_l := EM_MREQ.addr(12 downto 2);      -- get cache line addr
    iaddr_t := EM_MREQ.addr(21 downto 13);     -- get cache tag part
 
    icmem_tag_cea := '0';
    icmem_tag_ceb := '0';
    icmem_tag_wea := '0';
    icmem_tag_web := '0';
    icmem_tag_dib := r.addr_t;          -- default, local define whenver used
    icmem_dat_cea := '0';
    icmem_dat_ceb := '0';
    icmem_dat_wea := "0000";
    icmem_dat_web := "0000";
    icmem_val_dib := "0000";
    icmem_dat_dib := MEM_DO;            -- default, local define whenver used
 
    icmem_val_doa(0)            := CMEM_DOA_0(8);
    icmem_dat_doa( 7 downto  0) := CMEM_DOA_0(7 downto 0);
    icmem_val_doa(1)            := CMEM_DOA_1(8);
    icmem_dat_doa(15 downto  8) := CMEM_DOA_1(7 downto 0);
    icmem_val_doa(2)            := CMEM_DOA_2(8);
    icmem_dat_doa(23 downto 16) := CMEM_DOA_2(7 downto 0);
    icmem_val_doa(3)            := CMEM_DOA_3(8);
    icmem_dat_doa(31 downto 24) := CMEM_DOA_3(7 downto 0);
 
    itagok := '0';
    if CMEM_TAG_DOA = r.addr_t then  -- cache tag hit
      itagok := '1';
    end if;
    ivalok := '0';
    if (icmem_val_doa and r.be) = r.be then
      ivalok := '1';
    end if;
 
    iackr := '0';
    iackw := '0';
    ichit := '0';
    iosel := "11";                      -- default to ext. mem data
                                        -- this prevents U's from cache bram's
                                        -- to propagate to dout in beginning...
 
    imem_reqr := '0';
    imem_reqw := '0';
    imem_be   := r.be;
 
    case r.state is
      when s_idle =>                    -- s_idle: wait for req
        n.addr_w := iaddr_w;              -- capture address: word select
        n.addr_l := iaddr_l;              -- capture address: cache line addr
        n.addr_t := iaddr_t;              -- capture address: cache tag part
        n.be     := "0000";
        icmem_tag_cea := '1';             -- access cache tag port A
        icmem_dat_cea := '1';             -- access cache data port A
        if iaddr_w = '0' then             -- capture byte enables at 4 byte lvl
          n.be(1 downto 0) := EM_MREQ.be;
        else
          n.be(3 downto 2) := EM_MREQ.be;
        end if;
        n.di     := EM_MREQ.din;          -- capture data
 
        if EM_MREQ.req = '1' then         -- if access requested
          if EM_MREQ.we = '0' then          -- if READ requested
            n.state := s_read;                -- next: read
 
          else                              -- if WRITE requested
            icmem_tag_wea := '1';             -- write tag
            icmem_dat_wea := n.be;            -- write cache data
            n.state := s_write;               -- next: write
          end if;
        end if;
 
      when s_read =>                    -- s_read: read cycle
        iosel := '0' & r.addr_w;          -- output select: cache
        imem_be := "1111";                -- mem read: all 4 bytes
        if EM_MREQ.cancel = '0' then
          if FMISS='0' and itagok='1' and ivalok='1' then -- read tag&val hit
            iackr := '1';                   -- signal read acknowledge
            ichit := '1';                   -- signal cache hit
            n.state := s_idle;              -- next: back to idle 
          else                            -- read miss
            if MEM_BUSY = '0' then          -- if mem not busy
              imem_reqr :='1';                -- request mem read
              n.state := s_rmiss;             -- next: rmiss, wait for mem data
            end if;
          end if;
        else
          n.state := s_idle;              -- next: back to idle 
        end if;
 
      when s_rmiss =>                   -- s_rmiss: read cycle
        iosel := '1' & r.addr_w;          -- output select: memory
        icmem_tag_web := '1';             -- cache update: write tag
        icmem_tag_dib := r.addr_t;        -- cache update: new tag
        icmem_val_dib := "1111";          -- cache update: all valid
        icmem_dat_dib := MEM_DO;          -- cache update: data from mem
        icmem_dat_web := "1111";          -- cache update: write all 4 bytes
        if MEM_ACK_R = '1' then           -- mem data valid
          iackr := '1';                     -- signal read acknowledge
          icmem_tag_ceb := '1';             -- access cache tag  port B
          icmem_dat_ceb := '1';             -- access cache data port B
          n.state := s_idle;                -- next: back to idle
        end if;
 
      when s_write =>                   -- s_write: write cycle
        icmem_tag_dib := CMEM_TAG_DOA;    -- cache restore: last state 
        icmem_dat_dib := icmem_dat_doa;   -- cache restore: last state 
        if EM_MREQ.cancel = '0' then      -- request ok
          if MEM_BUSY = '0' then            -- if mem not busy
            if itagok = '0' then              -- if write tag miss
              icmem_dat_ceb := '1';             -- access cache (invalidate)
              icmem_dat_web := not r.be;        -- write missed bytes
              icmem_val_dib := "0000";          -- invalidate missed bytes
            end if;
            imem_reqw := '1';                 -- write back to main memory
            iackw := '1';                     -- and done
            n.state := s_idle;                -- next: back to idle
          end if;
 
        else                              -- request canceled -> restore
          icmem_tag_ceb := '1';             -- access cache line
          icmem_tag_web := '1';             -- write tag
          icmem_dat_ceb := '1';             -- access cache line
          icmem_dat_web := "1111";          -- restore cache line
          icmem_val_dib := icmem_val_doa;   -- cache restore: last state 
          n.state := s_idle;                -- next: back to idle          
        end if;  
 
      when others => null;
    end case;
 
    N_REGS <= n;
 
    CMEM_TAG_CEA <= icmem_tag_cea;
    CMEM_TAG_CEB <= icmem_tag_ceb;
    CMEM_TAG_WEA <= icmem_tag_wea;
    CMEM_TAG_WEB <= icmem_tag_web;
    CMEM_TAG_DIB <= icmem_tag_dib;
    CMEM_DAT_CEA <= icmem_dat_cea;
    CMEM_DAT_CEB <= icmem_dat_ceb;
    CMEM_DAT_WEA <= icmem_dat_wea;
    CMEM_DAT_WEB <= icmem_dat_web;
 
    CMEM_DIA_0(8)          <= '1';
    CMEM_DIA_0(7 downto 0) <= EM_MREQ.din( 7 downto 0);
    CMEM_DIA_1(8)          <= '1';
    CMEM_DIA_1(7 downto 0) <= EM_MREQ.din(15 downto 8);
    CMEM_DIA_2(8)          <= '1';
    CMEM_DIA_2(7 downto 0) <= EM_MREQ.din( 7 downto 0);
    CMEM_DIA_3(8)          <= '1';
    CMEM_DIA_3(7 downto 0) <= EM_MREQ.din(15 downto 8);
 
    CMEM_DIB_0(8)          <= icmem_val_dib(0);
    CMEM_DIB_0(7 downto 0) <= icmem_dat_dib(7 downto 0);
    CMEM_DIB_1(8)          <= icmem_val_dib(1);
    CMEM_DIB_1(7 downto 0) <= icmem_dat_dib(15 downto 8);
    CMEM_DIB_2(8)          <= icmem_val_dib(2);
    CMEM_DIB_2(7 downto 0) <= icmem_dat_dib(23 downto 16);
    CMEM_DIB_3(8)          <= icmem_val_dib(3);
    CMEM_DIB_3(7 downto 0) <= icmem_dat_dib(31 downto 24);
 
    EM_SRES <= em_sres_init;
    EM_SRES.ack_r <= iackr;
    EM_SRES.ack_w <= iackw;
    case iosel is
      when "00" => EM_SRES.dout <= icmem_dat_doa(15 downto  0);
      when "01" => EM_SRES.dout <= icmem_dat_doa(31 downto 16);
      when "10" => EM_SRES.dout <= MEM_DO(15 downto  0);
      when "11" => EM_SRES.dout <= MEM_DO(31 downto 16);
      when others => null;
    end case;
 
    CHIT  <= ichit;
 
    MEM_REQ  <= imem_reqr or imem_reqw;
    MEM_WE   <= imem_reqw;
    MEM_ADDR <= r.addr_t & r.addr_l;
    MEM_BE   <= imem_be;
    MEM_DI   <= r.di & r.di;
 
  end process proc_next;
 
end syn;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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