Skip to content

Commit

Permalink
fetch,loadstore: relax the constraints on L1 base and limit addresses.
Browse files Browse the repository at this point in the history
Instead of requiring powers of 2 for both, we now require that:
- the region size is a power of 2,
- the base address is a multiple of the region size.
  • Loading branch information
Jean-François Nguyen committed Jun 10, 2021
1 parent df1ea0f commit b2dd476
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 44 deletions.
26 changes: 16 additions & 10 deletions minerva/cache.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from nmigen import *
from nmigen.asserts import *
from nmigen.lib.coding import Encoder
from nmigen.utils import log2_int
from nmigen.utils import log2_int, bits_for


__all__ = ["L1Cache"]
Expand All @@ -18,17 +18,23 @@ def __init__(self, nways, nlines, nwords, base, limit):
if nways not in {1, 2}:
raise ValueError("nways must be 1 or 2, not {!r}".format(nways))

if not isinstance(base, int):
raise TypeError("base must be an integer, not {!r}".format(base))
if base not in range(0, 2**32) or base & base - 1:
raise ValueError("base must be 0 or a power of 2 (< 2**32), not {:#x}".format(base))
if not isinstance(limit, int):
raise TypeError("limit must be an integer, not {!r}".format(limit))
if limit not in range(1, 2**32 + 1) or limit & limit - 1:
raise ValueError("limit must be a power of 2 (<= 2**32), not {:#x}".format(limit))
if not isinstance(base, int) or base not in range(0, 2**32):
raise ValueError("base must be an integer between {:#x} and {:#x} inclusive, not {!r}"
.format(0, 2**32-1, base))
if limit not in range(0, 2**32):
raise ValueError("limit must be an integer between {:#x} and {:#x} inclusive, not {!r}"
.format(0, 2**32-1, limit))

if base >= limit:
raise ValueError("limit {:#x} must be greater than base {:#x}"
.format(limit, base))
if (limit - base) & (limit - base) - 1:
raise ValueError("limit - base must be a power of 2, not {:#x}"
.format(limit - base))
if base % (limit - base):
raise ValueError("base must be a multiple of limit - base, but {:#x} is not a multiple "
"of {:#x}"
.format(base, limit - base))

self.nways = nways
self.nlines = nlines
Expand All @@ -38,7 +44,7 @@ def __init__(self, nways, nlines, nwords, base, limit):

offsetbits = log2_int(nwords)
linebits = log2_int(nlines)
tagbits = log2_int(limit) - linebits - offsetbits - 2
tagbits = bits_for(limit) - linebits - offsetbits - 2

self.s1_addr = Record([("offset", offsetbits), ("line", linebits), ("tag", tagbits)])
self.s1_stall = Signal()
Expand Down
39 changes: 22 additions & 17 deletions minerva/units/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,23 +144,28 @@ def elaborate(self, platform):

a_icache_select = Signal()

# Test whether the target address is inside the L1 cache region. We use bit masks in order
# to avoid carry chains from arithmetic comparisons. This restricts the region boundaries
# to powers of 2.
with m.Switch(self.a_pc[2:]):
def addr_below(limit):
assert limit in range(1, 2**30 + 1)
range_bits = log2_int(limit)
const_bits = 30 - range_bits
return "{}{}".format("0" * const_bits, "-" * range_bits)

if self._icache.base >= 4:
with m.Case(addr_below(self._icache.base >> 2)):
m.d.comb += a_icache_select.eq(0)
with m.Case(addr_below(self._icache.limit >> 2)):
m.d.comb += a_icache_select.eq(1)
with m.Default():
m.d.comb += a_icache_select.eq(0)
# Test whether the target address is inside the L1 cache region. We use a bit mask in order
# to avoid carry chains from arithmetic comparisons. To this end, the base and limit
# addresses of the cached region must satisfy the following constraints:
# 1) the region size (i.e. ``limit - base``) must be a power of 2
# 2) ``base`` must be a multiple of the region size

def addr_between(base, limit):
assert base in range(1, 2**30 + 1)
assert limit in range(1, 2**30 + 1)
assert limit >= base
assert base % (limit - base) == 0
addr_width = log2_int(limit - base, need_pow2=True)
const_bits = 30 - addr_width
if const_bits > 0:
const_pat = "{:0{}b}".format(base >> addr_width, const_bits)
else:
const_pat = ""
return "{}{}".format(const_pat, "-" * addr_width)

icache_pattern = addr_between(self._icache.base >> 2, self._icache.limit >> 2)
with m.If(self.a_pc[2:].matches(icache_pattern)):
m.d.comb += a_icache_select.eq(1)

f_icache_select = Signal()
f_flush = Signal()
Expand Down
39 changes: 22 additions & 17 deletions minerva/units/loadstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,23 +201,28 @@ def elaborate(self, platform):

x_dcache_select = Signal()

# Test whether the target address is inside the L1 cache region. We use bit masks in order
# to avoid carry chains from arithmetic comparisons. This restricts the region boundaries
# to powers of 2.
with m.Switch(self.x_addr[2:]):
def addr_below(limit):
assert limit in range(1, 2**30 + 1)
range_bits = log2_int(limit)
const_bits = 30 - range_bits
return "{}{}".format("0" * const_bits, "-" * range_bits)

if self._dcache.base >= 4:
with m.Case(addr_below(self._dcache.base >> 2)):
m.d.comb += x_dcache_select.eq(0)
with m.Case(addr_below(self._dcache.limit >> 2)):
m.d.comb += x_dcache_select.eq(1)
with m.Default():
m.d.comb += x_dcache_select.eq(0)
# Test whether the target address is inside the L1 cache region. We use a bit mask in order
# to avoid carry chains from arithmetic comparisons. To this end, the base and limit
# addresses of the cached region must satisfy the following constraints:
# 1) the region size (i.e. ``limit - base``) must be a power of 2
# 2) ``base`` must be a multiple of the region size

def addr_between(base, limit):
assert base in range(1, 2**30 + 1)
assert limit in range(1, 2**30 + 1)
assert limit >= base
assert base % (limit - base) == 0
addr_width = log2_int(limit - base, need_pow2=True)
const_bits = 30 - addr_width
if const_bits > 0:
const_pat = "{:0{}b}".format(base >> addr_width, const_bits)
else:
const_pat = ""
return "{}{}".format(const_pat, "-" * addr_width)

dcache_pattern = addr_between(self._dcache.base >> 2, self._dcache.limit >> 2)
with m.If(self.x_addr[2:].matches(dcache_pattern)):
m.d.comb += x_dcache_select.eq(1)

m_dcache_select = Signal()
m_addr = Signal.like(self.x_addr)
Expand Down

0 comments on commit b2dd476

Please sign in to comment.