Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/Boneless-CPU
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6968ffe60683
Choose a base ref
...
head repository: whitequark/Boneless-CPU
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: b793d1bfc341
Choose a head ref
  • 1 commit
  • 6 files changed
  • 1 contributor

Commits on Jul 3, 2019

  1. Copy the full SHA
    b793d1b View commit details
Showing with 262 additions and 227 deletions.
  1. +0 −24 boneless/gateware/__init__.py
  2. +83 −110 boneless/gateware/alsru.py
  3. +83 −0 boneless/gateware/control.py
  4. +60 −56 boneless/gateware/core_v3.py
  5. +26 −27 boneless/gateware/decoder_v3.py
  6. +10 −10 boneless/test/test_alsru.py
24 changes: 0 additions & 24 deletions boneless/gateware/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +0,0 @@
import enum
from nmigen import *
from nmigen.tools import bits_for


__all__ = []


@enum.unique
class ControlEnum(enum.IntEnum):
@property
def pretty_name(self):
return self.name.replace("_", "-")

@classmethod
def signal(cls, **kwargs):
width = max(cls).bit_length()
def decoder(value):
try:
# return "{}/{:0{}b}".format(cls(value).pretty_name, value, width)
return cls(value).pretty_name
except ValueError:
return str(value)
return Signal(width, decoder=decoder, src_loc_at=1, **kwargs)
193 changes: 83 additions & 110 deletions boneless/gateware/alsru.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
from nmigen import *

from .control import *


__all__ = ["ALSRU", "ALSRU_4LUT"]


class ALSRU:
"""Arithmetical, logical, shift, and rotate unit."""

# defined by subclasses
BITS_OP = None
CTRL_A = None
CTRL_B = None
CTRL_nB = None
CTRL_AaB = None
CTRL_AoB = None
CTRL_AxB = None
CTRL_ApB = None
CTRL_AmB = None
CTRL_SL = None
CTRL_SR = None
# redefined by subclasses
class Op(MultiControlEnum):
A = ()
B = ()
nB = ()
AaB = ()
AoB = ()
AxB = ()
ApB = ()
AmB = ()
SL = ()
SR = ()

def __init__(self, width):
self.a = Signal(width)
@@ -33,31 +35,7 @@ def __init__(self, width):
self.si = Signal() # shift in
self.so = Signal() # shift out

self.op = None # defined by subclasses

@classmethod
def op_decoder(cls, word):
if word == cls.CTRL_A._as_const():
return "A"
if word == cls.CTRL_B._as_const():
return "B"
if word == cls.CTRL_nB._as_const():
return "~B"
if word == cls.CTRL_AaB._as_const():
return "A&B"
if word == cls.CTRL_AoB._as_const():
return "A|B"
if word == cls.CTRL_AxB._as_const():
return "A^B"
if word == cls.CTRL_ApB._as_const():
return "A+B"
if word == cls.CTRL_AmB._as_const():
return "A-B"
if word == cls.CTRL_SL._as_const():
return "R<<1"
if word == cls.CTRL_SR._as_const():
return "R>>1"
return "? {:0{}b}".format(word, cls.BITS_OP)
self.op = self.Op.signal() # redefined by subclasses


class ALSRU_4LUT(ALSRU, Elaboratable):
@@ -94,92 +72,87 @@ class ALSRU_4LUT(ALSRU, Elaboratable):
# R<<1: S=SLn-1 Y=S O=Y (pre-load R)
# R>>1: S=SRn+1 Y=S O=Y (pre-load R)

MUX_S_x = 0
MUX_S_L = 0b0
MUX_S_R = 0b1

MUX_X_x = 0
MUX_X_A = 0b00
MUX_X_AaB = 0b01
MUX_X_AoB = 0b10
MUX_X_AxB = 0b11

MUX_Y_0 = 0b00
MUX_Y_S = 0b01
MUX_Y_B = 0b10
MUX_Y_nB = 0b11

MUX_O_XpY = 0b0
MUX_O_Y = 0b1

BITS_OP = 6
CTRL_A = Cat(C(MUX_S_x, 1), C(MUX_X_A, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_B = Cat(C(MUX_S_x, 1), C(MUX_X_x, 2), C(MUX_Y_B, 2), C(MUX_O_Y, 1))
CTRL_nB = Cat(C(MUX_S_x, 1), C(MUX_X_x, 2), C(MUX_Y_nB, 2), C(MUX_O_Y, 1))
CTRL_AaB = Cat(C(MUX_S_x, 1), C(MUX_X_AaB, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_AoB = Cat(C(MUX_S_x, 1), C(MUX_X_AoB, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_AxB = Cat(C(MUX_S_x, 1), C(MUX_X_AxB, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_ApB = Cat(C(MUX_S_x, 1), C(MUX_X_A, 2), C(MUX_Y_B, 2), C(MUX_O_XpY, 1))
CTRL_AmB = Cat(C(MUX_S_x, 1), C(MUX_X_A, 2), C(MUX_Y_nB, 2), C(MUX_O_XpY, 1))
CTRL_SL = Cat(C(MUX_S_L, 1), C(MUX_X_x, 2), C(MUX_Y_S, 2), C(MUX_O_Y, 1))
CTRL_SR = Cat(C(MUX_S_R, 1), C(MUX_X_x, 2), C(MUX_Y_S, 2), C(MUX_O_Y, 1))

def __init__(self, width):
super().__init__(width)

self.s = Signal(width)
self.x = Signal(width)
self.y = Signal(width)

self.op = Record([
("s", 1),
("x", 2),
("y", 2),
("o", 1),
])
class MuxS(ControlEnum):
L = 0b0
R = 0b1
x = 0

class MuxX(ControlEnum):
A = 0b00
AaB = 0b01
AoB = 0b10
AxB = 0b11
x = 0

class MuxY(ControlEnum):
Z = 0b00
S = 0b01
B = 0b10
nB = 0b11

class MuxO(ControlEnum):
XpY = 0b0
Y = 0b1

class Op(MultiControlEnum, layout={"s":MuxS, "x":MuxX, "y":MuxY, "o":MuxO}):
A = ("x", "A", "Z", "XpY",)
B = ("x", "x", "B", "Y", )
nB = ("x", "x", "nB", "Y", )
AaB = ("x", "AaB", "Z", "XpY",)
AoB = ("x", "AoB", "Z", "XpY",)
AxB = ("x", "AxB", "Z", "XpY",)
ApB = ("x", "A", "B", "XpY",)
AmB = ("x", "A", "nB", "XpY",)
SL = ("L", "x", "S", "Y", )
SR = ("R", "x", "S", "Y", )

def elaborate(self, platform):
m = Module()

with m.Switch(self.op.s):
with m.Case(self.MUX_S_L):
m.d.comb += self.s.eq(Cat(self.si, self.r[:-1]))
op = self.Op.expand(m, self.op)

s = Signal.like(self.o)
with m.Switch(op.s):
with m.Case(self.MuxS.L):
m.d.comb += s.eq(Cat(self.si, self.r[:-1]))
m.d.comb += self.so.eq(self.r[-1])
with m.Case(self.MUX_S_R):
m.d.comb += self.s.eq(Cat(self.r[ 1:], self.si))
with m.Case(self.MuxS.R):
m.d.comb += s.eq(Cat(self.r[ 1:], self.si))
m.d.comb += self.so.eq(self.r[ 0])

with m.Switch(self.op.x):
with m.Case(self.MUX_X_AaB):
m.d.comb += self.x.eq(self.a & self.b)
with m.Case(self.MUX_X_AoB):
m.d.comb += self.x.eq(self.a | self.b)
with m.Case(self.MUX_X_AxB):
m.d.comb += self.x.eq(self.a ^ self.b)
with m.Case(self.MUX_X_A):
m.d.comb += self.x.eq(self.a)

with m.Switch(self.op.y):
with m.Case(self.MUX_Y_0):
m.d.comb += self.y.eq(0)
with m.Case(self.MUX_Y_S):
m.d.comb += self.y.eq(self.s)
with m.Case(self.MUX_Y_B):
m.d.comb += self.y.eq(self.b)
with m.Case(self.MUX_Y_nB):
m.d.comb += self.y.eq(~self.b)
x = Signal.like(self.o)
with m.Switch(op.x):
with m.Case(self.MuxX.AaB):
m.d.comb += x.eq(self.a & self.b)
with m.Case(self.MuxX.AoB):
m.d.comb += x.eq(self.a | self.b)
with m.Case(self.MuxX.AxB):
m.d.comb += x.eq(self.a ^ self.b)
with m.Case(self.MuxX.A):
m.d.comb += x.eq(self.a)

y = Signal.like(self.o)
with m.Switch(op.y):
with m.Case(self.MuxY.Z):
m.d.comb += y.eq(0)
with m.Case(self.MuxY.S):
m.d.comb += y.eq(s)
with m.Case(self.MuxY.B):
m.d.comb += y.eq(self.b)
with m.Case(self.MuxY.nB):
m.d.comb += y.eq(~self.b)

p = Signal.like(self.o)
m.d.comb += Cat(p, self.co).eq(self.x + self.y + self.ci)
m.d.comb += Cat(p, self.co).eq(x + y + self.ci)

with m.Switch(self.op.o):
with m.Case(self.MUX_O_XpY):
with m.Switch(op.o):
with m.Case(self.MuxO.XpY):
m.d.comb += self.o.eq(p)
with m.Case(self.MUX_O_Y):
m.d.comb += self.o.eq(self.y)
with m.Case(self.MuxO.Y):
m.d.comb += self.o.eq(y)

# http://teaching.idallen.com/cst8214/08w/notes/overflow.txt
with m.Switch(Cat(self.x[-1], self.y[-1], self.o[-1])):
with m.Switch(Cat(x[-1], y[-1], self.o[-1])):
with m.Case(0b100):
m.d.comb += self.vo.eq(1)
with m.Case(0b011):
83 changes: 83 additions & 0 deletions boneless/gateware/control.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import enum
from nmigen import *


__all__ = ["ControlEnum", "MultiControlEnum"]


# We have to do an annoying metaclass dance because there's no @classproperty.
class ControlEnumMeta(enum.EnumMeta):
@property
def width(cls):
return max(cls).bit_length()


@enum.unique
class ControlEnum(enum.IntEnum, metaclass=ControlEnumMeta):
@classmethod
def decoder(cls, value):
try:
return cls(value).name.replace("_", "-")
except ValueError:
return str(value)

@classmethod
def signal(cls, **kwargs):
return Signal(cls.width, decoder=cls.decoder, src_loc_at=1, **kwargs)

def __repr__(self):
return "<{}: {:0{}b}>".format(self.name, self.value, self.width)


# We have to do an annoying metaclass dance because we want to do something like:
#
# class MuxA(ControlEnum): ...
# class MuxB(ControlEnum): ...
# class Mode(MultiControlEnum):
# FOO = (MuxA.X, MuxB.Y)
#
# but by the time we're inside the body of `Mode` it is no longer possible to access the names from
# the outer scope, so we can't easily name `MuxA` for example, so we rewrite it as:
#
# class Mode(MultiControlEnum, layout=[MuxA, MuxB]):
# FOO = ("X", "Y")
class MultiControlEnumMeta(ControlEnumMeta):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
return super().__prepare__(name, bases)

def __new__(cls, name, bases, classdict, layout=None):
if layout is not None:
classdict, old_classdict = type(classdict)(), classdict

offsets = []
offset = 0
for enum in layout.values():
offsets.append(offset)
offset += enum.width

for key in old_classdict:
if key.startswith("_"):
classdict[key] = old_classdict[key]
else:
value = 0
for item, enum, offset in zip(old_classdict[key], layout.values(), offsets):
value |= enum[item] << offset
classdict[key] = value

@classmethod
def expand(cls, m, signal):
rec = Record([(name, enum.width) for (name, enum) in layout.items()],
src_loc_at=1)
for name, enum in layout.items():
rec[name].decoder = enum.decoder
m.d.comb += rec.eq(signal)
return rec
classdict["expand"] = expand

return super().__new__(cls, name, bases, classdict)


class MultiControlEnum(ControlEnum, metaclass=MultiControlEnumMeta):
def foo(self):
pass
Loading